State)
{
int p = 0;
programCounter = State[p++];
programCounter |= (ushort)(State[p++] << 8);
addressBus = State[p++];
addressBus |= (ushort)(State[p++] << 8);
temporaryAddress = State[p++];
temporaryAddress |= (ushort)(State[p++] << 8);
OAMAddressBus = State[p++];
OAMAddressBus |= (ushort)(State[p++] << 8);
PPU_v = State[p++];
PPU_v |= (ushort)(State[p++] << 8);
PPU_t = State[p++];
PPU_t |= (ushort)(State[p++] << 8);
totalCycles = State[p++];
totalCycles |= (State[p++] << 8);
totalCycles |= (State[p++] << 16);
totalCycles |= (State[p++] << 24);
PPUClock = State[p++];
CPUClock = State[p++];
operationCycle = State[p++];
opCode = State[p++];
dl = State[p++];
dataBus = State[p++];
A = State[p++];
X = State[p++];
Y = State[p++];
stackPointer = State[p++];
status = State[p++];
flag_Carry = (status & 1) == 1;
flag_Zero = ((status & 0x02) >> 1) == 1;
flag_Interrupt = ((status & 0x04) >> 2) == 1;
flag_Decimal = ((status & 0x08) >> 3) == 1;
flag_Overflow = ((status & 0x40) >> 6) == 1;
flag_Negative = ((status & 0x80) >> 7) == 1;
specialBus = State[p++];
H = State[p++];
IgnoreH = (State[p++] & 1) == 1;
CPU_Read = (State[p++] & 1) == 1;
DoBRK = (State[p++] & 1) == 1;
DoNMI = (State[p++] & 1) == 1;
DoIRQ = (State[p++] & 1) == 1;
DoReset = (State[p++] & 1) == 1;
DoOAMDMA = (State[p++] & 1) == 1;
FirstCycleOfOAMDMA = (State[p++] & 1) == 1;
DoDMCDMA = (State[p++] & 1) == 1;
DMCDMADelay = State[p++];
CannotRunDMCDMARightNow = State[p++];
DMAPage = State[p++];
DMAAddress = State[p++];
APU_ControllerPortsStrobing = (State[p++] & 1) == 1;
APU_ControllerPortsStrobed = (State[p++] & 1) == 1;
ControllerPort1 = State[p++];
ControllerPort2 = State[p++];
ControllerShiftRegister1 = State[p++];
ControllerShiftRegister2 = State[p++];
Controller1ShiftCounter = State[p++];
Controller2ShiftCounter = State[p++];
dataPinsAreNotFloating = (State[p++] & 1) == 1;
APU_PutCycle = (State[p++] & 1) == 1;
APU_Status_DMCInterrupt = (State[p++] & 1) == 1;
APU_Status_FrameInterrupt = (State[p++] & 1) == 1;
APU_Status_DMC = (State[p++] & 1) == 1;
APU_Status_DelayedDMC = (State[p++] & 1) == 1;
APU_Status_Noise = (State[p++] & 1) == 1;
APU_Status_Triangle = (State[p++] & 1) == 1;
APU_Status_Pulse2 = (State[p++] & 1) == 1;
APU_Status_Pulse1 = (State[p++] & 1) == 1;
Clearing_APU_FrameInterrupt = (State[p++] & 1) == 1;
APU_DelayedDMC4015 = State[p++];
APU_ImplicitAbortDMC4015 = (State[p++] & 1) == 1;
APU_SetImplicitAbortDMC4015 = (State[p++] & 1) == 1;
for (int i = 0; i < APU_Register.Length; i++) { APU_Register[i] = State[p++]; }
APU_FrameCounterMode = (State[p++] & 1) == 1;
APU_FrameCounterInhibitIRQ = (State[p++] & 1) == 1;
APU_FrameCounterReset = State[p++];
APU_Framecounter = State[p++];
APU_Framecounter |= (ushort)(State[p++] << 8);
APU_QuarterFrameClock = (State[p++] & 1) == 1;
APU_HalfFrameClock = (State[p++] & 1) == 1;
APU_Envelope_StartFlag = (State[p++] & 1) == 1;
APU_Envelope_DividerClock = (State[p++] & 1) == 1;
APU_Envelope_DecayLevel = State[p++];
APU_LengthCounter_Pulse1 = State[p++];
APU_LengthCounter_Pulse2 = State[p++];
APU_LengthCounter_Triangle = State[p++];
APU_LengthCounter_Noise = State[p++];
APU_LengthCounter_HaltPulse1 = (State[p++] & 1) == 1;
APU_LengthCounter_HaltPulse2 = (State[p++] & 1) == 1;
APU_LengthCounter_HaltTriangle = (State[p++] & 1) == 1;
APU_LengthCounter_HaltNoise = (State[p++] & 1) == 1;
APU_LengthCounter_ReloadPulse1 = (State[p++] & 1) == 1;
APU_LengthCounter_ReloadPulse2 = (State[p++] & 1) == 1;
APU_LengthCounter_ReloadTriangle = (State[p++] & 1) == 1;
APU_LengthCounter_ReloadNoise = (State[p++] & 1) == 1;
APU_LengthCounter_ReloadValuePulse1 = State[p++];
APU_LengthCounter_ReloadValuePulse2 = State[p++];
APU_LengthCounter_ReloadValueTriangle = State[p++];
APU_LengthCounter_ReloadValueNoise = State[p++];
APU_ChannelTimer_Pulse1 = State[p++];
APU_ChannelTimer_Pulse1 |= (ushort)(State[p++] << 8);
APU_ChannelTimer_Pulse2 = State[p++];
APU_ChannelTimer_Pulse2 |= (ushort)(State[p++] << 8);
APU_ChannelTimer_Triangle = State[p++];
APU_ChannelTimer_Triangle |= (ushort)(State[p++] << 8);
APU_ChannelTimer_Noise = State[p++];
APU_ChannelTimer_Noise |= (ushort)(State[p++] << 8);
APU_ChannelTimer_DMC = State[p++];
APU_ChannelTimer_DMC |= (ushort)(State[p++] << 8);
APU_DMC_EnableIRQ = (State[p++] & 1) == 1;
APU_DMC_Loop = (State[p++] & 1) == 1;
APU_DMC_Rate = State[p++];
APU_DMC_Rate |= (ushort)(State[p++] << 8);
APU_DMC_Output = State[p++];
APU_DMC_SampleAddress = State[p++];
APU_DMC_SampleAddress |= (ushort)(State[p++] << 8);
APU_DMC_SampleLength = State[p++];
APU_DMC_SampleLength |= (ushort)(State[p++] << 8);
APU_DMC_BytesRemaining = State[p++];
APU_DMC_BytesRemaining |= (ushort)(State[p++] << 8);
APU_DMC_Buffer = State[p++];
APU_DMC_AddressCounter = State[p++];
APU_DMC_AddressCounter |= (ushort)(State[p++] << 8);
APU_DMC_Shifter = State[p++];
APU_DMC_ShifterBitsRemaining = State[p++];
APU_Silent = (State[p++] & 1) == 1;
SecondaryOAMSize = State[p++];
OAM2Address = State[p++];
SecondaryOAMFull = (State[p++] & 1) == 1;
SpriteEvaluationTick = State[p++];
OAMAddressOverflowedDuringSpriteEvaluation = (State[p++] & 1) == 1;
OAM2Address = State[p++];
PPUBus = State[p++];
for (int i = 0; i < 8; i++)
{
PPUBusDecay[i] = State[p++];
PPUBusDecay[i] |= (State[p++] << 8);
PPUBusDecay[i] |= (State[p++] << 16);
PPUBusDecay[i] |= (State[p++] << 24);
}
PPUOAMAddress = State[p++];
PPUStatus_VBlank = (State[p++] & 1) == 1;
PPUStatus_SpriteZeroHit = (State[p++] & 1) == 1;
PPUStatus_SpriteOverflow = (State[p++] & 1) == 1;
PPUStatus_PendingSpriteZeroHit = (State[p++] & 1) == 1;
PPUStatus_PendingSpriteZeroHit2 = (State[p++] & 1) == 1;
PPUStatus_SpriteZeroHit_Delayed = (State[p++] & 1) == 1;
PPUStatus_SpriteOverflow_Delayed = (State[p++] & 1) == 1;
PPU_Spritex16 = (State[p++] & 1) == 1;
PPU_Scanline = State[p++];
PPU_Scanline |= (ushort)(State[p++] << 8);
PPU_Dot = State[p++];
PPU_Dot |= (ushort)(State[p++] << 8);
PPU_VRegisterChangedOutOfVBlank = (State[p++] & 1) == 1;
PPU_OAMCorruptionRenderingDisabledOutOfVBlank = (State[p++] & 1) == 1;
PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = (State[p++] & 1) == 1;
PPU_PendingOAMCorruption = (State[p++] & 1) == 1;
PPU_OAMCorruptionIndex = State[p++];
PPU_OAMCorruptionRenderingEnabledOutOfVBlank = (State[p++] & 1) == 1;
PPU_OAMEvaluationCorruptionOddCycle = (State[p++] & 1) == 1;
PPU_OAMEvaluationObjectInRange = (State[p++] & 1) == 1;
PPU_OAMEvaluationObjectInXRange = (State[p++] & 1) == 1;
PPU_PaletteCorruptionRenderingDisabledOutOfVBlank = (State[p++] & 1) == 1;
PPU_AttributeLatchRegister = State[p++];
PPU_BackgroundAttributeShiftRegisterL = State[p++];
PPU_BackgroundAttributeShiftRegisterL |= (ushort)(State[p++] << 8);
PPU_BackgroundAttributeShiftRegisterH = State[p++];
PPU_BackgroundAttributeShiftRegisterH |= (ushort)(State[p++] << 8);
PPU_BackgroundPatternShiftRegisterL = State[p++];
PPU_BackgroundPatternShiftRegisterL |= (ushort)(State[p++] << 8);
PPU_BackgroundPatternShiftRegisterH = State[p++];
PPU_BackgroundPatternShiftRegisterH |= (ushort)(State[p++] << 8);
PPU_FineXScroll = State[p++];
for (int i = 0; i < 8; i++) { PPU_SpriteShiftRegisterL[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpriteShiftRegisterH[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpriteAttribute[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpritePattern[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpriteXposition[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpriteYposition[i] = State[p++]; }
for (int i = 0; i < 8; i++) { PPU_SpriteShifterCounter[i] = State[p++]; }
PPU_NextScanlineContainsSpriteZero = (State[p++] & 1) == 1;
PPU_CurrentScanlineContainsSpriteZero = (State[p++] & 1) == 1;
PPU_SpritePatternL = State[p++];
PPU_SpritePatternH = State[p++];
PPU_Mask_Greyscale = (State[p++] & 1) == 1;
PPU_Mask_8PxShowBackground = (State[p++] & 1) == 1;
PPU_Mask_8PxShowSprites = (State[p++] & 1) == 1;
PPU_Mask_ShowBackground = (State[p++] & 1) == 1;
PPU_Mask_ShowSprites = (State[p++] & 1) == 1;
PPU_Mask_EmphasizeRed = (State[p++] & 1) == 1;
PPU_Mask_EmphasizeGreen = (State[p++] & 1) == 1;
PPU_Mask_EmphasizeBlue = (State[p++] & 1) == 1;
PPU_Mask_ShowBackground_Delayed = (State[p++] & 1) == 1;
PPU_Mask_ShowSprites_Delayed = (State[p++] & 1) == 1;
PPU_Mask_ShowBackground_Instant = (State[p++] & 1) == 1;
PPU_Mask_ShowSprites_Instant = (State[p++] & 1) == 1;
PPU_LowBitPlane = State[p++];
PPU_HighBitPlane = State[p++];
PPU_Attribute = State[p++];
PPU_CanDetectSpriteZeroHit = (State[p++] & 1) == 1;
PPU_A12_Prev = (State[p++] & 1) == 1;
PPU_OddFrame = (State[p++] & 1) == 1;
PaletteRAMAddress = State[p++];
ThisDotReadFromPaletteRAM = (State[p++] & 1) == 1;
NMI_PinsSignal = (State[p++] & 1) == 1;
NMI_PreviousPinsSignal = (State[p++] & 1) == 1;
IRQ_LevelDetector = (State[p++] & 1) == 1;
NMILine = (State[p++] & 1) == 1;
IRQLine = (State[p++] & 1) == 1;
CopyV = (State[p++] & 1) == 1;
SkippedPreRenderDot341 = (State[p++] & 1) == 1;
OamCorruptedOnOddCycle = (State[p++] & 1) == 1;
PPU_OAMLatch = State[p++];
PPU_RenderTemp = State[p++];
PPU_Commit_NametableFetch = (State[p++] & 1) == 1;
PPU_Commit_AttributeFetch = (State[p++] & 1) == 1;
PPU_Commit_PatternLowFetch = (State[p++] & 1) == 1;
PPU_Commit_PatternHighFetch = (State[p++] & 1) == 1;
PPU_VRAM_MysteryAddress = State[p++];
PPU_VRAM_MysteryAddress |= (ushort)(State[p++] << 8);
PPU_AddressBus = State[p++];
PPU_AddressBus |= (ushort)(State[p++] << 8);
PPU_Update2006Delay = State[p++];
PPU_Update2005Delay = State[p++];
PPU_Update2005Value = State[p++];
PPU_Update2001Value = State[p++];
PPU_Update2006Value = State[p++];
PPU_Update2006Value |= (ushort)(State[p++] << 8);
PPU_Update2006Value_Temp = State[p++];
PPU_Update2006Value_Temp |= (ushort)(State[p++] << 8);
PPU_WasRenderingBefore2001Write = (State[p++] & 1) == 1;
PPU_ReadBuffer = State[p++];
PPUAddrLatch = (State[p++] & 1) == 1;
PPUControlIncrementMode32 = (State[p++] & 1) == 1;
PPUControl_NMIEnabled = (State[p++] & 1) == 1;
PPU_PatternSelect_Sprites = (State[p++] & 1) == 1;
PPU_PatternSelect_Background = (State[p++] & 1) == 1;
PPU_PendingVBlank = (State[p++] & 1) == 1;
PPU_VSET = (State[p++] & 1) == 1;
PPU_VSET_Latch1 = (State[p++] & 1) == 1;
PPU_VSET_Latch2 = (State[p++] & 1) == 1;
PPU_Read2002 = (State[p++] & 1) == 1;
OAMDMA_Aligned = (State[p++] & 1) == 1;
OAMDMA_Halt = (State[p++] & 1) == 1;
DMCDMA_Halt = (State[p++] & 1) == 1;
OAM_InternalBus = State[p++];
PPU_PatternAddressRegister_CHR = State[p++];
PPU_PatternAddressRegister_CHR |= (ushort)(State[p++] << 8);
PPU_ALE = (State[p++] & 1) == 1;
PPU_OctalLatch = State[p++];
PPU_2007_Read = (State[p++] & 1) == 1;
PPU_2007_Read_SR = (State[p++] & 1) == 1;
for (int i = 0; i < PPU_2007_Read_Latches.Length; i++) { PPU_2007_Read_Latches[i] = (State[p++] & 1) == 1; }
PPU_2007_PD_RB = (State[p++] & 1) == 1;
PPU_2007_ReadALE = (State[p++] & 1) == 1;
PPU_2007_Read_H0_Latch = (State[p++] & 1) == 1;
PPU_2007_Read_XRB = (State[p++] & 1) == 1;
PPU_READ = (State[p++] & 1) == 1;
PPU_2007_Write = (State[p++] & 1) == 1;
PPU_2007_Write_SR = (State[p++] & 1) == 1;
for (int i = 0; i < PPU_2007_Write_Latches.Length; i++) { PPU_2007_Write_Latches[i] = (State[p++] & 1) == 1; }
PPU_2007_DB_PAR = (State[p++] & 1) == 1;
PPU_2007_WriteALE = (State[p++] & 1) == 1;
PPU_2007_TStep_Latch = (State[p++] & 1) == 1;
PPU_2007_TStep = (State[p++] & 1) == 1;
PPU_2007_BLNK_Latch = (State[p++] & 1) == 1;
PPU_2007_PaletteRAMEnable = (State[p++] & 1) == 1;
PPU_2007_WriteData = State[p++];
PPU_WRITE = (State[p++] & 1) == 1;
PPU_Update2001Delay = State[p++]; //TOMPORARY
PPU_Update2001OAMCorruptionDelay = State[p++]; //TOMPORARY
PPU_Update2001EmphasisBitsDelay = State[p++]; //TOMPORARY
for (int i = 0; i < RAM.Length; i++) { RAM[i] = State[p++]; }
for (int i = 0; i < VRAM.Length; i++) { VRAM[i] = State[p++]; }
for (int i = 0; i < OAM.Length; i++) { OAM[i] = State[p++]; }
for (int i = 0; i < OAM2.Length; i++) { OAM2[i] = State[p++]; }
for (int i = 0; i < PaletteRAM.Length; i++) { PaletteRAM[i] = State[p++]; }
Cart.MapperChip.LoadMapperRegisters(State, p, out p);
}
public void Dispose()
{
Cart = null;
Screen.Dispose();
BorderedScreen.Dispose();
NTSCScreen.Dispose();
BorderedNTSCScreen.Dispose();
}
}
public class DirectBitmap : IDisposable
{
// This class was copied from Stack Overflow
// Writing to the standard Bitmap class is slow, so this class exists as a faster alternative.
public Bitmap Bitmap { get; private set; }
public Int32[] Bits { get; private set; }
public bool Disposed { get; private set; }
public int Height { get; private set; }
public int Width { get; private set; }
protected GCHandle BitsHandle { get; private set; }
public DirectBitmap(int width, int height)
{
Width = width;
Height = height;
Bits = new Int32[width * height];
BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject());
}
public void SetPixel(int x, int y, Color color)
{
int index = x + (y * Width);
int col = color.ToArgb();
Bits[index] = col;
}
public void SetPixel(int x, int y, int colorRGBA)
{
int index = x + (y * Width);
Bits[index] = colorRGBA;
}
public Color GetPixel(int x, int y)
{
int index = x + (y * Width);
int col = Bits[index];
Color result = Color.FromArgb(col);
return result;
}
public void Dispose()
{
if (Disposed) return;
Disposed = true;
Bitmap.Dispose();
BitsHandle.Free();
}
}
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2025 Chris Siebert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Program.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TriCNES
{
internal static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TriCNESGUI());
}
}
}
================================================
FILE: Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TriCNES")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TriCNES")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b53c8a3b-8f4f-4837-99a0-47d7d9fe757f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: Properties/Resources.Designer.cs
================================================
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
namespace TriCNES.Properties
{
///
/// A strongly-typed resource class, for looking up localized strings, etc.
///
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
///
/// Returns the cached ResourceManager instance used by this class.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TriCNES.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
///
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
================================================
FILE: Properties/Resources.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================
FILE: Properties/Settings.Designer.cs
================================================
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
//------------------------------------------------------------------------------
namespace TriCNES.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
================================================
FILE: Properties/Settings.settings
================================================
================================================
FILE: README.md
================================================
# TriCNES
TriCNES, or "Coin's Contrabulous Cartswapulator", is a Nintendo Entertainment System emulator written by Chris "100th_Coin" Siebert with a focus on test-driven accuracy. This emulator was originally made in order to experiment with a theorhetical arbitary code exploit I created titled "Intercycle Cartridge Swapping" where the NES cartridge is replaced every CPU cycle in order to run custom code. Intercycle Cartridge Swapping was later verified to work on real hardware by Youtube user Decrazyo.
This NES emulator was built from the ground up starting from a blank .net winforms project
# Limitations
This emulator does not produce audio.
This emulator only accepts inputs in the form of a TAS file.
This emulator can only run NTSC cartridges properly.
This emulator only supports the following mapper chips:
* 0: NROM
* 1: MMC1
* 2: UxROM
* 3: CNROM
* 4: MMC3 (MMC6 support in the dev build)
* 7: AOROM
* 9: MMC2 (dev build)
* 69: Sunsoft FME-7
# Supported TAS file types
Due to varying emulator accuracy, this emulator is not guaranteed to sync all TAS files. Despite this, it supports loading inputs from the following formats:
* .3c2 (TriCNES) (dev build)
* .3c3 (TriCNES TAS Timeline) (dev build)
* .bk2 (Bizhawk)
* .tasproj (Bizhawk's TAStudio)
* .fm2 (FCEUX)
* .fm3 (FCEUX's TAS Editor)
* .fmv (Famtasia)
* .r08 (Replay Device)
In addition to those TAS file types, my emulator can also load my very own intercycle-cart-swapping TAS format, .3ct.
# The .3ct TAS file format
TAS files that were made with the intention of swapping cartridges between cycles are stored in the following format.
The first line of the file is an integer, indicating how many cartridges are being used for this TAS. This integer will be called 'n'.
The following 'n' lines are local file paths to the ROMs you wish to use. This will set up an array of cartridges.
The remaining lines until the end of the file are in the following format: "x y" where an integer 'x' is seperated from an integer 'y' with a space.
When the TAS is being played back, before CPU cycle 'x', swap to the cartridge at index 'y' into the cartridge array.
Here's an example:
5
Super Mario Bros. [!].nes
Dash Galaxy in the Alien Asylum (U) [!].nes
Kung Fu (JU) [!].nes
Pipe Dream (U) [!].nes
Super Mario Bros. 3 (U) (V1.1) [!].nes
6 0
7 1
8 2
9 3
10 4
In this example, there are 5 cartridges. Before cycle 6, the emulator will swap to `Super Mario Bros. [!].nes`, as that is index 0 into the cartridge array. Before cycle 7, the emulator will swap to index 1, `Dash Galaxy in the Alien Asylum (U) [!].nes`, and so on.
# Screenshots



================================================
FILE: TriCNES.csproj
================================================
Debug
AnyCPU
{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}
WinExe
TriCNES
TriCNES
v4.8
512
true
true
AnyCPU
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
AnyCPU
pdbonly
true
bin\Release\
TRACE
prompt
4
icon.ico
8
packages\ppy.SDL2-CS.1.0.82\lib\netstandard2.0\SDL2-CS.dll
True
Form
TASProperties.cs
Form
TASProperties3ct.cs
Form
TriCHexEditor.cs
Form
TriCNESGUI.cs
Form
TriCNTViewer.cs
Form
TriCTASTimeline.cs
Form
TriCTraceLogger.cs
TASProperties.cs
TASProperties3ct.cs
TriCHexEditor.cs
TriCNESGUI.cs
ResXFileCodeGenerator
Resources.Designer.cs
Designer
True
Resources.resx
TriCNTViewer.cs
TriCTASTimeline.cs
TriCTraceLogger.cs
SettingsSingleFileGenerator
Settings.Designer.cs
True
Settings.settings
True
Always
================================================
FILE: TriCNES.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35013.160
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TriCNES", "TriCNES.csproj", "{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ED419257-E7C5-4EAC-80C7-78320132F3F4}"
ProjectSection(SolutionItems) = preProject
icon.ico = icon.ico
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0A57AF3A-82C3-46E2-B3C8-8550E13D4B10}
EndGlobalSection
EndGlobal
================================================
FILE: forms/TASProperties.Designer.cs
================================================
namespace TriCNES
{
partial class TASProperties
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TASProperties));
this.b_RunTAS = new System.Windows.Forms.Button();
this.tb_FilePath = new System.Windows.Forms.TextBox();
this.l_FilePath = new System.Windows.Forms.Label();
this.rb_LatchFiltering = new System.Windows.Forms.RadioButton();
this.rb_ClockFiltering = new System.Windows.Forms.RadioButton();
this.panel1 = new System.Windows.Forms.Panel();
this.TASPropTooltips = new System.Windows.Forms.ToolTip(this.components);
this.cb_ClockAlignment = new System.Windows.Forms.ComboBox();
this.cb_CpuClock = new System.Windows.Forms.ComboBox();
this.b_BrowseFile = new System.Windows.Forms.Button();
this.l_InputCount = new System.Windows.Forms.Label();
this.l_FamtasiaWarning = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.cb_fceuxFrame0 = new System.Windows.Forms.CheckBox();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// b_RunTAS
//
this.b_RunTAS.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.b_RunTAS.Location = new System.Drawing.Point(24, 255);
this.b_RunTAS.Name = "b_RunTAS";
this.b_RunTAS.Size = new System.Drawing.Size(300, 40);
this.b_RunTAS.TabIndex = 0;
this.b_RunTAS.Text = "Run TAS";
this.b_RunTAS.UseVisualStyleBackColor = true;
this.b_RunTAS.Click += new System.EventHandler(this.b_RunTAS_Click);
//
// tb_FilePath
//
this.tb_FilePath.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.tb_FilePath.Location = new System.Drawing.Point(53, 6);
this.tb_FilePath.Name = "tb_FilePath";
this.tb_FilePath.ReadOnly = true;
this.tb_FilePath.Size = new System.Drawing.Size(206, 20);
this.tb_FilePath.TabIndex = 1;
//
// l_FilePath
//
this.l_FilePath.AutoSize = true;
this.l_FilePath.Location = new System.Drawing.Point(26, 9);
this.l_FilePath.Name = "l_FilePath";
this.l_FilePath.Size = new System.Drawing.Size(23, 13);
this.l_FilePath.TabIndex = 2;
this.l_FilePath.Text = "File";
//
// rb_LatchFiltering
//
this.rb_LatchFiltering.AutoSize = true;
this.rb_LatchFiltering.Location = new System.Drawing.Point(5, 3);
this.rb_LatchFiltering.Name = "rb_LatchFiltering";
this.rb_LatchFiltering.Size = new System.Drawing.Size(91, 17);
this.rb_LatchFiltering.TabIndex = 3;
this.rb_LatchFiltering.TabStop = true;
this.rb_LatchFiltering.Text = "Latch Filtering";
this.TASPropTooltips.SetToolTip(this.rb_LatchFiltering, "Latch filtering will provide a single input per frame.");
this.rb_LatchFiltering.UseVisualStyleBackColor = true;
//
// rb_ClockFiltering
//
this.rb_ClockFiltering.AutoSize = true;
this.rb_ClockFiltering.Location = new System.Drawing.Point(5, 26);
this.rb_ClockFiltering.Name = "rb_ClockFiltering";
this.rb_ClockFiltering.Size = new System.Drawing.Size(91, 17);
this.rb_ClockFiltering.TabIndex = 4;
this.rb_ClockFiltering.TabStop = true;
this.rb_ClockFiltering.Text = "Clock Filtering";
this.TASPropTooltips.SetToolTip(this.rb_ClockFiltering, "Clock filtering will provide multiple inputs per frame. This is used in \"subframe" +
"\" TASes.");
this.rb_ClockFiltering.UseVisualStyleBackColor = true;
//
// panel1
//
this.panel1.Controls.Add(this.rb_LatchFiltering);
this.panel1.Controls.Add(this.rb_ClockFiltering);
this.panel1.Location = new System.Drawing.Point(24, 200);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(100, 49);
this.panel1.TabIndex = 6;
//
// cb_ClockAlignment
//
this.cb_ClockAlignment.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_ClockAlignment.FormattingEnabled = true;
this.cb_ClockAlignment.Items.AddRange(new object[] {
"Phase 0",
"Phase 1",
"Phase 2",
"Phase 3"});
this.cb_ClockAlignment.Location = new System.Drawing.Point(176, 174);
this.cb_ClockAlignment.Name = "cb_ClockAlignment";
this.cb_ClockAlignment.Size = new System.Drawing.Size(65, 21);
this.cb_ClockAlignment.TabIndex = 10;
this.TASPropTooltips.SetToolTip(this.cb_ClockAlignment, "Some runs may desync depending on alignment. Different emulators use different al" +
"ignments. Only change this if you know what you are doing.");
//
// cb_CpuClock
//
this.cb_CpuClock.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_CpuClock.FormattingEnabled = true;
this.cb_CpuClock.Items.AddRange(new object[] {
"Phase 0",
"Phase 1",
"Phase 2",
"Phase 3",
"Phase 4",
"Phase 5",
"Phase 6",
"Phase 7",
"Phase 8",
"Phase 9",
"Phase 10",
"Phase 11"});
this.cb_CpuClock.Location = new System.Drawing.Point(176, 151);
this.cb_CpuClock.Name = "cb_CpuClock";
this.cb_CpuClock.Size = new System.Drawing.Size(65, 21);
this.cb_CpuClock.TabIndex = 13;
this.TASPropTooltips.SetToolTip(this.cb_CpuClock, "Some runs may desync depending on alignment. Different emulators use different al" +
"ignments. Only change this if you know what you are doing.");
//
// b_BrowseFile
//
this.b_BrowseFile.Location = new System.Drawing.Point(265, 6);
this.b_BrowseFile.Name = "b_BrowseFile";
this.b_BrowseFile.Size = new System.Drawing.Size(59, 21);
this.b_BrowseFile.TabIndex = 7;
this.b_BrowseFile.Text = "Browse...";
this.b_BrowseFile.UseVisualStyleBackColor = true;
//
// l_InputCount
//
this.l_InputCount.AutoSize = true;
this.l_InputCount.Location = new System.Drawing.Point(26, 29);
this.l_InputCount.Name = "l_InputCount";
this.l_InputCount.Size = new System.Drawing.Size(44, 13);
this.l_InputCount.TabIndex = 8;
this.l_InputCount.Text = "0 inputs";
//
// l_FamtasiaWarning
//
this.l_FamtasiaWarning.AutoSize = true;
this.l_FamtasiaWarning.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.l_FamtasiaWarning.Location = new System.Drawing.Point(12, 73);
this.l_FamtasiaWarning.Name = "l_FamtasiaWarning";
this.l_FamtasiaWarning.Size = new System.Drawing.Size(325, 26);
this.l_FamtasiaWarning.TabIndex = 9;
this.l_FamtasiaWarning.Text = "Warning!\r\nFamtasia is an old emulator, and the TAS is not guaranteed to sync!";
this.l_FamtasiaWarning.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(21, 177);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(149, 13);
this.label3.TabIndex = 11;
this.label3.Text = "PPU / Master clock alignment";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(21, 154);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(149, 13);
this.label1.TabIndex = 12;
this.label1.Text = "CPU / Master clock alignment";
//
// cb_fceuxFrame0
//
this.cb_fceuxFrame0.AutoSize = true;
this.cb_fceuxFrame0.Checked = true;
this.cb_fceuxFrame0.CheckState = System.Windows.Forms.CheckState.Checked;
this.cb_fceuxFrame0.Location = new System.Drawing.Point(24, 124);
this.cb_fceuxFrame0.Name = "cb_fceuxFrame0";
this.cb_fceuxFrame0.Size = new System.Drawing.Size(175, 17);
this.cb_fceuxFrame0.TabIndex = 14;
this.cb_fceuxFrame0.Text = "Use FCEUX\'s Frame 0 behavior";
this.TASPropTooltips.SetToolTip(this.cb_fceuxFrame0, "FCEUX inaccurately emulates the first frame from the beginning of VBlank rather t" +
"han the end.\r\nUnchecking this box can potentially lead to a desync, though it wi" +
"ll be more accurate.");
this.cb_fceuxFrame0.UseVisualStyleBackColor = true;
//
// TASProperties
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(350, 307);
this.Controls.Add(this.cb_fceuxFrame0);
this.Controls.Add(this.cb_CpuClock);
this.Controls.Add(this.label1);
this.Controls.Add(this.label3);
this.Controls.Add(this.cb_ClockAlignment);
this.Controls.Add(this.l_FamtasiaWarning);
this.Controls.Add(this.l_InputCount);
this.Controls.Add(this.b_BrowseFile);
this.Controls.Add(this.panel1);
this.Controls.Add(this.l_FilePath);
this.Controls.Add(this.tb_FilePath);
this.Controls.Add(this.b_RunTAS);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "TASProperties";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "TAS Properties";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button b_RunTAS;
private System.Windows.Forms.TextBox tb_FilePath;
private System.Windows.Forms.Label l_FilePath;
private System.Windows.Forms.RadioButton rb_LatchFiltering;
private System.Windows.Forms.RadioButton rb_ClockFiltering;
private System.Windows.Forms.ToolTip TASPropTooltips;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button b_BrowseFile;
private System.Windows.Forms.Label l_InputCount;
private System.Windows.Forms.Label l_FamtasiaWarning;
private System.Windows.Forms.ComboBox cb_ClockAlignment;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox cb_CpuClock;
private System.Windows.Forms.CheckBox cb_fceuxFrame0;
}
}
================================================
FILE: forms/TASProperties.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Compression;
namespace TriCNES
{
public partial class TASProperties : Form
{
public TASProperties()
{
InitializeComponent();
}
public string TasFilePath;
public ushort[] TasInputLog;
public bool[] TasResetLog;
public TriCNESGUI MainGUI;
public bool SubframeInputs()
{
return rb_ClockFiltering.Checked;
}
public bool UseFCEUXFrame0Timing() // this only applies to TASes using the .fm2 or .fm3 file format.
{
return cb_fceuxFrame0.Checked;
}
public byte GetPPUClockPhase()
{
return (byte)cb_ClockAlignment.SelectedIndex;
}
public byte GetCPUClockPhase()
{
return (byte)cb_CpuClock.SelectedIndex;
}
public string extension;
public void Init()
{
tb_FilePath.Text = TasFilePath;
// determine file type
extension = Path.GetExtension(TasFilePath);
// create list of inputs from the tas file, and make any settings changes if needed.
byte[] ByteArray = File.ReadAllBytes(TasFilePath);
List TASInputs = new List(); // Low byte is player 1, High byte is player 2.
rb_ClockFiltering.Checked = false;
rb_LatchFiltering.Checked = true;
l_FamtasiaWarning.Visible = false;
cb_ClockAlignment.SelectedIndex = 0;
cb_ClockAlignment.Update();
cb_CpuClock.SelectedIndex = 0;
cb_CpuClock.Update();
cb_fceuxFrame0.Enabled = false;
switch (extension)
{
case ".bk2":
case ".tasproj":
{
cb_CpuClock.SelectedIndex = 8;
cb_CpuClock.Update();
}
break;
case ".fm2":
{
cb_fceuxFrame0.Enabled = true;
// change the alignment to use FCEUX's
cb_CpuClock.SelectedIndex = 0;
cb_CpuClock.Update();
}
break;
case ".fm3":
{
}
break;
case ".fmv":
{
l_FamtasiaWarning.Visible = true;
}
break;
case ".r08":
{
}
break;
case ".3c2":
{
}
break;
case ".3c3":
{
}
break;
// TODO: ask if the .tasd file format is a thing yet
}
List Resets = new List();
TASInputs = MainGUI.ParseTasFile(TasFilePath, out Resets);
// okay cool, now we have the entire input log.
TasInputLog = TASInputs.ToArray();
TasResetLog = Resets.ToArray();
l_InputCount.Text = TasInputLog.Length + " Inputs";
}
private void b_RunTAS_Click(object sender, EventArgs e)
{
MainGUI.StartTAS();
}
}
}
================================================
FILE: forms/TASProperties.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
17, 17
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TASProperties3ct.Designer.cs
================================================
namespace TriCNES
{
partial class TASProperties3ct
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TASProperties3ct));
this.cb_CpuClock = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.cb_ClockAlignment = new System.Windows.Forms.ComboBox();
this.l_InputCount = new System.Windows.Forms.Label();
this.b_BrowseFile = new System.Windows.Forms.Button();
this.l_FilePath = new System.Windows.Forms.Label();
this.tb_FilePath = new System.Windows.Forms.TextBox();
this.b_RunTAS = new System.Windows.Forms.Button();
this.b_LoadCartridges = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.rb_FromPOW = new System.Windows.Forms.RadioButton();
this.rb_FromRES = new System.Windows.Forms.RadioButton();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// cb_CpuClock
//
this.cb_CpuClock.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_CpuClock.FormattingEnabled = true;
this.cb_CpuClock.Items.AddRange(new object[] {
"Phase 0",
"Phase 1",
"Phase 2",
"Phase 3",
"Phase 4",
"Phase 5",
"Phase 6",
"Phase 7",
"Phase 8",
"Phase 9",
"Phase 10",
"Phase 11"});
this.cb_CpuClock.Location = new System.Drawing.Point(177, 56);
this.cb_CpuClock.Name = "cb_CpuClock";
this.cb_CpuClock.Size = new System.Drawing.Size(65, 21);
this.cb_CpuClock.TabIndex = 24;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(22, 59);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(149, 13);
this.label1.TabIndex = 23;
this.label1.Text = "CPU / Master clock alignment";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(22, 82);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(149, 13);
this.label3.TabIndex = 22;
this.label3.Text = "PPU / Master clock alignment";
//
// cb_ClockAlignment
//
this.cb_ClockAlignment.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cb_ClockAlignment.FormattingEnabled = true;
this.cb_ClockAlignment.Items.AddRange(new object[] {
"Phase 0",
"Phase 1",
"Phase 2",
"Phase 3"});
this.cb_ClockAlignment.Location = new System.Drawing.Point(177, 79);
this.cb_ClockAlignment.Name = "cb_ClockAlignment";
this.cb_ClockAlignment.Size = new System.Drawing.Size(65, 21);
this.cb_ClockAlignment.TabIndex = 21;
//
// l_InputCount
//
this.l_InputCount.AutoSize = true;
this.l_InputCount.Location = new System.Drawing.Point(27, 32);
this.l_InputCount.Name = "l_InputCount";
this.l_InputCount.Size = new System.Drawing.Size(44, 13);
this.l_InputCount.TabIndex = 19;
this.l_InputCount.Text = "0 inputs";
//
// b_BrowseFile
//
this.b_BrowseFile.Location = new System.Drawing.Point(266, 9);
this.b_BrowseFile.Name = "b_BrowseFile";
this.b_BrowseFile.Size = new System.Drawing.Size(59, 21);
this.b_BrowseFile.TabIndex = 18;
this.b_BrowseFile.Text = "Browse...";
this.b_BrowseFile.UseVisualStyleBackColor = true;
//
// l_FilePath
//
this.l_FilePath.AutoSize = true;
this.l_FilePath.Location = new System.Drawing.Point(27, 12);
this.l_FilePath.Name = "l_FilePath";
this.l_FilePath.Size = new System.Drawing.Size(23, 13);
this.l_FilePath.TabIndex = 16;
this.l_FilePath.Text = "File";
//
// tb_FilePath
//
this.tb_FilePath.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.tb_FilePath.Location = new System.Drawing.Point(54, 9);
this.tb_FilePath.Name = "tb_FilePath";
this.tb_FilePath.ReadOnly = true;
this.tb_FilePath.Size = new System.Drawing.Size(206, 20);
this.tb_FilePath.TabIndex = 15;
//
// b_RunTAS
//
this.b_RunTAS.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.b_RunTAS.Enabled = false;
this.b_RunTAS.Location = new System.Drawing.Point(25, 212);
this.b_RunTAS.Name = "b_RunTAS";
this.b_RunTAS.Size = new System.Drawing.Size(300, 40);
this.b_RunTAS.TabIndex = 14;
this.b_RunTAS.Text = "Run TAS";
this.b_RunTAS.UseVisualStyleBackColor = true;
this.b_RunTAS.Click += new System.EventHandler(this.b_RunTAS_Click);
//
// b_LoadCartridges
//
this.b_LoadCartridges.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.b_LoadCartridges.Location = new System.Drawing.Point(25, 154);
this.b_LoadCartridges.Name = "b_LoadCartridges";
this.b_LoadCartridges.Size = new System.Drawing.Size(300, 40);
this.b_LoadCartridges.TabIndex = 25;
this.b_LoadCartridges.Text = "Load Cartridges";
this.b_LoadCartridges.UseVisualStyleBackColor = true;
this.b_LoadCartridges.Click += new System.EventHandler(this.b_LoadCartridges_Click);
//
// panel1
//
this.panel1.Controls.Add(this.rb_FromPOW);
this.panel1.Controls.Add(this.rb_FromRES);
this.panel1.Location = new System.Drawing.Point(25, 98);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(100, 49);
this.panel1.TabIndex = 26;
//
// rb_FromPOW
//
this.rb_FromPOW.AutoSize = true;
this.rb_FromPOW.Location = new System.Drawing.Point(5, 3);
this.rb_FromPOW.Name = "rb_FromPOW";
this.rb_FromPOW.Size = new System.Drawing.Size(92, 17);
this.rb_FromPOW.TabIndex = 3;
this.rb_FromPOW.TabStop = true;
this.rb_FromPOW.Text = "From POWER";
this.rb_FromPOW.UseVisualStyleBackColor = true;
//
// rb_FromRES
//
this.rb_FromRES.AutoSize = true;
this.rb_FromRES.Location = new System.Drawing.Point(5, 26);
this.rb_FromRES.Name = "rb_FromRES";
this.rb_FromRES.Size = new System.Drawing.Size(87, 17);
this.rb_FromRES.TabIndex = 4;
this.rb_FromRES.TabStop = true;
this.rb_FromRES.Text = "From RESET";
this.rb_FromRES.UseVisualStyleBackColor = true;
//
// TASProperties3ct
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(350, 264);
this.Controls.Add(this.panel1);
this.Controls.Add(this.b_LoadCartridges);
this.Controls.Add(this.cb_CpuClock);
this.Controls.Add(this.label1);
this.Controls.Add(this.label3);
this.Controls.Add(this.cb_ClockAlignment);
this.Controls.Add(this.l_InputCount);
this.Controls.Add(this.b_BrowseFile);
this.Controls.Add(this.l_FilePath);
this.Controls.Add(this.tb_FilePath);
this.Controls.Add(this.b_RunTAS);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "TASProperties3ct";
this.Text = "3CT TAS Properties";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox cb_CpuClock;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.ComboBox cb_ClockAlignment;
private System.Windows.Forms.Label l_InputCount;
private System.Windows.Forms.Button b_BrowseFile;
private System.Windows.Forms.Label l_FilePath;
private System.Windows.Forms.TextBox tb_FilePath;
private System.Windows.Forms.Button b_RunTAS;
private System.Windows.Forms.Button b_LoadCartridges;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.RadioButton rb_FromPOW;
private System.Windows.Forms.RadioButton rb_FromRES;
}
}
================================================
FILE: forms/TASProperties3ct.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using TriCNES.mappers;
namespace TriCNES
{
public partial class TASProperties3ct : Form
{
public TASProperties3ct()
{
InitializeComponent();
}
public string TasFilePath;
public ushort[] TasInputLog;
public TriCNESGUI MainGUI;
public byte GetPPUClockPhase()
{
return (byte)cb_ClockAlignment.SelectedIndex;
}
public byte GetCPUClockPhase()
{
return (byte)cb_CpuClock.SelectedIndex;
}
public bool FromRESET()
{
return rb_FromRES.Checked;
}
public Cartridge[] CartridgeArray;
public void Init()
{
tb_FilePath.Text = TasFilePath;
cb_ClockAlignment.SelectedIndex = 0;
cb_ClockAlignment.Update();
cb_CpuClock.SelectedIndex = 0;
cb_CpuClock.Update();
rb_FromPOW.Checked = true;
rb_FromPOW.Update();
}
Cartridge BackupCart;
private void b_RunTAS_Click(object sender, EventArgs e)
{
if (rb_FromPOW.Checked)
{
int i = 0;
while (i < CartridgeArray.Length)
{
CartridgeArray[i].PRGRAM = new byte[0x2000];
CartridgeArray[i].CHRRAM = new byte[0x2000];
Mapper MapperChip;
// clear all mapper stuff.
switch (CartridgeArray[i].MemoryMapper)
{
default:
case 0: MapperChip = new Mapper_NROM(); break;
case 1: MapperChip = new Mapper_MMC1(); break;
case 2: MapperChip = new Mapper_UxROM(); break;
case 3: MapperChip = new Mapper_CNROM(); break;
case 4: MapperChip = new Mapper_MMC3(); break;
case 7: MapperChip = new Mapper_AOROM(); break;
case 9: MapperChip = new Mapper_MMC2(); break;
case 69: MapperChip = new Mapper_FME7(); break;
}
MapperChip.Cart = CartridgeArray[i];
CartridgeArray[i].MapperChip = MapperChip;
i++;
}
}
MainGUI.Start3CTTAS();
}
public List CyclesToSwapOn;
public List CartsToSwapIn;
private void b_LoadCartridges_Click(object sender, EventArgs e)
{
bool error = false;
// check if rom folder is empty
string Dir = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"roms\"))
{
Dir += @"roms\";
if(Directory.GetFiles(Dir).Length == 0)
{
MessageBox.Show("Loading a .3ct TAS requires your roms to be located in the TriCNES roms folder.");
return;
}
}
// rom folder isn't empty!
StringReader SR = new StringReader(File.ReadAllText(tb_FilePath.Text));
string l = SR.ReadLine();
int count = int.Parse(l);
CartridgeArray = new Cartridge[count];
int i = 0;
while(i < count)
{
l = SR.ReadLine();
if(File.Exists(Dir+l))
{
if(i ==0)
{
BackupCart = new Cartridge(Dir + l);
}
if (MainGUI.EMU != null && MainGUI.EMU.Cart.Name == (Dir + l))
{
CartridgeArray[i] = MainGUI.EMU.Cart; // If running a TAS from RESET, we want to use the currently loaded cartridge
}
else
{
CartridgeArray[i] = new Cartridge(Dir + l);
}
}
else
{
MessageBox.Show("TriCNES roms folder is missing a required ROM for this TAS!\n\nMissing ROM: \"" + l + "\"");
return;
}
i++;
}
// if all carts are now loaded.
// let's also prepare the cycles to swap on, and the carts to swap in
CyclesToSwapOn = new List();
CartsToSwapIn = new List();
l = SR.ReadLine();
while (l != null)
{
// the format here is:
//x y
//x and y could be any length, but there's a space between them.
string s = l.Substring(0, l.IndexOf(" "));
CyclesToSwapOn.Add(int.Parse(s));
s = l.Remove(0,s.Length+1);
CartsToSwapIn.Add(int.Parse(s));
l = SR.ReadLine();
}
b_RunTAS.Enabled = true;
}
}
}
================================================
FILE: forms/TASProperties3ct.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TriCHexEditor.Designer.cs
================================================
namespace TriCNES
{
partial class TriCHexEditor
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCHexEditor));
this.pb_hexView = new System.Windows.Forms.PictureBox();
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.scopeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.rAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cPUAddressSpaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.vRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.pPUAddressSpaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.oAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.paletteRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.copyToClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)(this.pb_hexView)).BeginInit();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// pb_hexView
//
this.pb_hexView.Location = new System.Drawing.Point(12, 37);
this.pb_hexView.Name = "pb_hexView";
this.pb_hexView.Size = new System.Drawing.Size(312, 512);
this.pb_hexView.TabIndex = 0;
this.pb_hexView.TabStop = false;
//
// vScrollBar1
//
this.vScrollBar1.LargeChange = 32;
this.vScrollBar1.Location = new System.Drawing.Point(327, 57);
this.vScrollBar1.Maximum = 128;
this.vScrollBar1.Name = "vScrollBar1";
this.vScrollBar1.Size = new System.Drawing.Size(17, 492);
this.vScrollBar1.TabIndex = 1;
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem,
this.settingsToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(356, 24);
this.menuStrip1.TabIndex = 2;
this.menuStrip1.Text = "menuStrip1";
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.scopeToolStripMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
this.settingsToolStripMenuItem.Text = "Settings";
//
// scopeToolStripMenuItem
//
this.scopeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.rAMToolStripMenuItem,
this.cPUAddressSpaceToolStripMenuItem,
this.vRAMToolStripMenuItem,
this.pPUAddressSpaceToolStripMenuItem,
this.oAMToolStripMenuItem,
this.paletteRAMToolStripMenuItem});
this.scopeToolStripMenuItem.Name = "scopeToolStripMenuItem";
this.scopeToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.scopeToolStripMenuItem.Text = "Scope";
//
// rAMToolStripMenuItem
//
this.rAMToolStripMenuItem.Checked = true;
this.rAMToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.rAMToolStripMenuItem.Name = "rAMToolStripMenuItem";
this.rAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.rAMToolStripMenuItem.Text = "RAM";
this.rAMToolStripMenuItem.Click += new System.EventHandler(this.rAMToolStripMenuItem_Click);
//
// cPUAddressSpaceToolStripMenuItem
//
this.cPUAddressSpaceToolStripMenuItem.Name = "cPUAddressSpaceToolStripMenuItem";
this.cPUAddressSpaceToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.cPUAddressSpaceToolStripMenuItem.Text = "CPU Address Space";
this.cPUAddressSpaceToolStripMenuItem.Click += new System.EventHandler(this.cPUAddressSpaceToolStripMenuItem_Click);
//
// vRAMToolStripMenuItem
//
this.vRAMToolStripMenuItem.Name = "vRAMToolStripMenuItem";
this.vRAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.vRAMToolStripMenuItem.Text = "VRAM";
this.vRAMToolStripMenuItem.Click += new System.EventHandler(this.vRAMToolStripMenuItem_Click);
//
// pPUAddressSpaceToolStripMenuItem
//
this.pPUAddressSpaceToolStripMenuItem.Name = "pPUAddressSpaceToolStripMenuItem";
this.pPUAddressSpaceToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.pPUAddressSpaceToolStripMenuItem.Text = "PPU Address Space";
this.pPUAddressSpaceToolStripMenuItem.Click += new System.EventHandler(this.pPUAddressSpaceToolStripMenuItem_Click);
//
// oAMToolStripMenuItem
//
this.oAMToolStripMenuItem.Name = "oAMToolStripMenuItem";
this.oAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.oAMToolStripMenuItem.Text = "OAM";
this.oAMToolStripMenuItem.Click += new System.EventHandler(this.oAMToolStripMenuItem_Click);
//
// paletteRAMToolStripMenuItem
//
this.paletteRAMToolStripMenuItem.Name = "paletteRAMToolStripMenuItem";
this.paletteRAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
this.paletteRAMToolStripMenuItem.Text = "Palette RAM";
this.paletteRAMToolStripMenuItem.Click += new System.EventHandler(this.paletteRAMToolStripMenuItem_Click);
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.copyToClipboardToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
//
// copyToClipboardToolStripMenuItem
//
this.copyToClipboardToolStripMenuItem.Name = "copyToClipboardToolStripMenuItem";
this.copyToClipboardToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.copyToClipboardToolStripMenuItem.Text = "Copy to Clipboard";
this.copyToClipboardToolStripMenuItem.Click += new System.EventHandler(this.copyToClipboardToolStripMenuItem_Click);
//
// TriCHexEditor
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(356, 561);
this.Controls.Add(this.vScrollBar1);
this.Controls.Add(this.pb_hexView);
this.Controls.Add(this.menuStrip1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1;
this.MinimumSize = new System.Drawing.Size(16, 135);
this.Name = "TriCHexEditor";
this.Text = "Hex Editor";
((System.ComponentModel.ISupportInitialize)(this.pb_hexView)).EndInit();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox pb_hexView;
private System.Windows.Forms.VScrollBar vScrollBar1;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem scopeToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem rAMToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem cPUAddressSpaceToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem vRAMToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem pPUAddressSpaceToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem oAMToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem paletteRAMToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem copyToClipboardToolStripMenuItem;
}
}
================================================
FILE: forms/TriCHexEditor.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace TriCNES
{
public partial class TriCHexEditor : Form
{
public TriCHexEditor()
{
InitializeComponent();
hexBitmap = new Bitmap(312,512);
G = Graphics.FromImage(hexBitmap);
Font_Consolas = new Font("Consolas", 8);
Scope = "RAM";
Resize += TriCHexEditor_Resize;
vScrollBar1.ValueChanged += Scrollbar_ValueChanged;
}
public TriCNESGUI MainGUI;
public Graphics G;
public Bitmap hexBitmap;
public Font Font_Consolas;
public int Scroll;
public string Scope;
ScopeType scopeType = ScopeType.RAM;
public int MaxRows = 32;
private void TriCHexEditor_Resize(object sender, EventArgs e)
{
MaxRows = (Size.Height - 115) / 15;
hexBitmap = new Bitmap(312, Size.Height - 88);
pb_hexView.Size = new Size(312, Size.Height - 88);
vScrollBar1.Size = new Size(vScrollBar1.Width,Size.Height-108);
vScrollBar1.LargeChange = MaxRows;
G = Graphics.FromImage(hexBitmap);
RefreshEntireHexView();
}
private void Scrollbar_ValueChanged(object sender, EventArgs e)
{
Scroll = vScrollBar1.Value;
RefreshEntireHexView();
}
enum ScopeType
{
RAM,
CPU_Address_Space,
VRAM,
PPU_Address_Space,
OAM,
Palette_RAM
};
public void Update()
{
MethodInvoker upd = delegate
{
RefreshEntireHexView();
};
try
{
this.Invoke(upd);
}
catch(Exception e)
{
}
}
public void RefreshEntireHexView()
{
if(MainGUI.EMU == null)
{
return;
}
vScrollBar1.Enabled = MaxRows < vScrollBar1.Maximum;
vScrollBar1.Update();
G.FillRectangle(Brushes.WhiteSmoke,new Rectangle(0,0, 312, Size.Height - 88));
G.DrawString(Scope + ":", Font_Consolas, Brushes.Black, new Point(0, 0));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(" " + x.ToString("X"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 16));
}
switch (scopeType)
{
case ScopeType.RAM:
{
int i = Scroll*0x10;
int y = 0;
while(i < 0x800 && y < MaxRows)
{
// print $xy0:
G.DrawString("$" + (i).ToString("X3") + ":", Font_Consolas, Brushes.Black, new Point(0, 32+y*15));
for(int x=0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.RAM[i].ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x*15, 32 + y * 15));
i++;
}
y++;
}
}
break;
case ScopeType.CPU_Address_Space:
{
int i = Scroll * 0x10;
int y = 0;
while (i < 0x10000 && y < MaxRows)
{
// print $xyz0:
G.DrawString("$" + (i).ToString("X4") + ":", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.Observe((ushort)i).ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));
i++;
}
y++;
}
}
break;
case ScopeType.VRAM:
{
int i = Scroll * 0x10;
int y = 0;
while (i < 0x800 && y < MaxRows)
{
// print $xy0:
G.DrawString("$" + (i).ToString("X3") + ":", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.VRAM[i].ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));
i++;
}
y++;
}
}
break;
case ScopeType.PPU_Address_Space:
{
int i = Scroll * 0x10;
int y = 0;
while (i < 0x4000 && y < MaxRows)
{
// print $xyz0:
G.DrawString("$" + (i).ToString("X4") + ":", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.ObservePPU((ushort)i).ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));
i++;
}
y++;
}
}
break;
case ScopeType.OAM:
{
int i = Scroll * 0x10;
int y = 0;
while (i < 0x100 && y < MaxRows)
{
// print $xy0:
G.DrawString("$" + (i).ToString("X3") + ":", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.OAM[i].ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));
i++;
}
y++;
}
}
break;
case ScopeType.Palette_RAM:
{
int i = Scroll * 0x10;
int y = 0;
while (i < 0x20 && y < MaxRows)
{
// print $xy0:
G.DrawString("$" + (i).ToString("X3") + ":", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));
for (int x = 0; x < 0x10; x++)
{
G.DrawString(MainGUI.EMU.PaletteRAM[i].ToString("X2"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));
i++;
}
y++;
}
}
break;
}
pb_hexView.Image = hexBitmap;
pb_hexView.Update();
}
void ChangeScope(ScopeType st)
{
Scroll = 0;
vScrollBar1.Value = 0;
vScrollBar1.Update();
rAMToolStripMenuItem.Checked = st == ScopeType.RAM;
cPUAddressSpaceToolStripMenuItem.Checked = st == ScopeType.CPU_Address_Space;
vRAMToolStripMenuItem.Checked = st == ScopeType.VRAM;
pPUAddressSpaceToolStripMenuItem.Checked = st == ScopeType.PPU_Address_Space;
oAMToolStripMenuItem.Checked = st == ScopeType.OAM;
paletteRAMToolStripMenuItem.Checked = st == ScopeType.Palette_RAM;
scopeType = st;
switch(st)
{
case ScopeType.RAM:
vScrollBar1.Maximum = 0x80; Scope = "RAM"; break;
case ScopeType.CPU_Address_Space:
vScrollBar1.Maximum = 0x1000; Scope = "CPU Address Space"; break;
case ScopeType.VRAM:
vScrollBar1.Maximum = 0x80; Scope = "VRAM"; break;
case ScopeType.PPU_Address_Space:
vScrollBar1.Maximum = 0x400; Scope = "PPU Address Space"; break;
case ScopeType.OAM:
vScrollBar1.Maximum = 0x10; Scope = "OAM"; break;
case ScopeType.Palette_RAM:
vScrollBar1.Maximum = 0x2; Scope = "Palette RAM"; break;
}
RefreshEntireHexView();
}
private void rAMToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.RAM);
}
private void cPUAddressSpaceToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.CPU_Address_Space);
}
private void vRAMToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.VRAM);
}
private void pPUAddressSpaceToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.PPU_Address_Space);
}
private void oAMToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.OAM);
}
private void paletteRAMToolStripMenuItem_Click(object sender, EventArgs e)
{
ChangeScope(ScopeType.Palette_RAM);
}
private void copyToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
for(int i = 0; i < vScrollBar1.Maximum*0x10;i++)
{
switch (scopeType)
{
case ScopeType.RAM:
sb.Append(MainGUI.EMU.RAM[i].ToString("X2") + " "); break;
case ScopeType.CPU_Address_Space:
sb.Append(MainGUI.EMU.Observe((ushort)i).ToString("X2") + " "); break;
case ScopeType.VRAM:
sb.Append(MainGUI.EMU.VRAM[i].ToString("X2") + " "); break;
case ScopeType.PPU_Address_Space:
sb.Append(MainGUI.EMU.ObservePPU((ushort)i).ToString("X2") + " "); break;
case ScopeType.OAM:
sb.Append(MainGUI.EMU.OAM[i].ToString("X2") + " "); break;
case ScopeType.Palette_RAM:
sb.Append(MainGUI.EMU.PaletteRAM[i].ToString("X2") + " "); break;
}
}
Clipboard.SetText(sb.ToString());
}
}
}
================================================
FILE: forms/TriCHexEditor.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
17, 17
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TriCNESGUI.Designer.cs
================================================
using System.Threading;
using System.Windows.Forms;
namespace TriCNES
{
partial class TriCNESGUI
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCNESGUI));
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.consoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.loadROMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.resetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.powerCycleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.screenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveStateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.loadStateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.loadTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.load3ctToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.pPUClockToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.phase0ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.phase1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.phase2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.phase3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.decodeNTSCSignalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.trueToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.showRawSignalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.falseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewBoarderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolstrip_ViewBorders_True = new System.Windows.Forms.ToolStripMenuItem();
this.toolstrip_ViewBorders_False = new System.Windows.Forms.ToolStripMenuItem();
this.viewScaleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem4 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem5 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem6 = new System.Windows.Forms.ToolStripMenuItem();
this.xToolStripMenuItem7 = new System.Windows.Forms.ToolStripMenuItem();
this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.traceLoggerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nametableViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.tASTimelineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.pb_Screen = new TriCNES.PictureBoxWithInterpolationMode();
this.hexEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pb_Screen)).BeginInit();
this.SuspendLayout();
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.consoleToolStripMenuItem,
this.tASToolStripMenuItem,
this.settingsToolStripMenuItem,
this.toolsToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(256, 24);
this.menuStrip1.TabIndex = 0;
this.menuStrip1.Text = "menuStrip1";
//
// consoleToolStripMenuItem
//
this.consoleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.loadROMToolStripMenuItem,
this.resetToolStripMenuItem,
this.powerCycleToolStripMenuItem,
this.screenshotToolStripMenuItem,
this.saveStateToolStripMenuItem,
this.loadStateToolStripMenuItem});
this.consoleToolStripMenuItem.Name = "consoleToolStripMenuItem";
this.consoleToolStripMenuItem.Size = new System.Drawing.Size(62, 20);
this.consoleToolStripMenuItem.Text = "Console";
//
// loadROMToolStripMenuItem
//
this.loadROMToolStripMenuItem.Name = "loadROMToolStripMenuItem";
this.loadROMToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.loadROMToolStripMenuItem.Text = "Load ROM";
this.loadROMToolStripMenuItem.Click += new System.EventHandler(this.loadROMToolStripMenuItem_Click);
//
// resetToolStripMenuItem
//
this.resetToolStripMenuItem.Name = "resetToolStripMenuItem";
this.resetToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.resetToolStripMenuItem.Text = "Reset";
this.resetToolStripMenuItem.Click += new System.EventHandler(this.resetToolStripMenuItem_Click);
//
// powerCycleToolStripMenuItem
//
this.powerCycleToolStripMenuItem.Name = "powerCycleToolStripMenuItem";
this.powerCycleToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.powerCycleToolStripMenuItem.Text = "Power Cycle";
this.powerCycleToolStripMenuItem.Click += new System.EventHandler(this.powerCycleToolStripMenuItem_Click);
//
// screenshotToolStripMenuItem
//
this.screenshotToolStripMenuItem.Name = "screenshotToolStripMenuItem";
this.screenshotToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.screenshotToolStripMenuItem.Text = "Screenshot";
this.screenshotToolStripMenuItem.Click += new System.EventHandler(this.screenshotToolStripMenuItem_Click);
//
// saveStateToolStripMenuItem
//
this.saveStateToolStripMenuItem.Name = "saveStateToolStripMenuItem";
this.saveStateToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.saveStateToolStripMenuItem.Text = "Save State";
this.saveStateToolStripMenuItem.Click += new System.EventHandler(this.saveStateToolStripMenuItem_Click);
//
// loadStateToolStripMenuItem
//
this.loadStateToolStripMenuItem.Name = "loadStateToolStripMenuItem";
this.loadStateToolStripMenuItem.Size = new System.Drawing.Size(139, 22);
this.loadStateToolStripMenuItem.Text = "Load State";
this.loadStateToolStripMenuItem.Click += new System.EventHandler(this.loadStateToolStripMenuItem_Click);
//
// tASToolStripMenuItem
//
this.tASToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.loadTASToolStripMenuItem,
this.load3ctToolStripMenuItem});
this.tASToolStripMenuItem.Name = "tASToolStripMenuItem";
this.tASToolStripMenuItem.Size = new System.Drawing.Size(38, 20);
this.tASToolStripMenuItem.Text = "TAS";
//
// loadTASToolStripMenuItem
//
this.loadTASToolStripMenuItem.Name = "loadTASToolStripMenuItem";
this.loadTASToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
this.loadTASToolStripMenuItem.Text = "Load TAS";
this.loadTASToolStripMenuItem.Click += new System.EventHandler(this.loadTASToolStripMenuItem_Click);
//
// load3ctToolStripMenuItem
//
this.load3ctToolStripMenuItem.Name = "load3ctToolStripMenuItem";
this.load3ctToolStripMenuItem.Size = new System.Drawing.Size(144, 22);
this.load3ctToolStripMenuItem.Text = "Load .3ct TAS";
this.load3ctToolStripMenuItem.Click += new System.EventHandler(this.load3ctToolStripMenuItem_Click);
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.pPUClockToolStripMenuItem,
this.decodeNTSCSignalsToolStripMenuItem,
this.viewBoarderToolStripMenuItem,
this.viewScaleToolStripMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
this.settingsToolStripMenuItem.Text = "Settings";
//
// pPUClockToolStripMenuItem
//
this.pPUClockToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.phase0ToolStripMenuItem,
this.phase1ToolStripMenuItem,
this.phase2ToolStripMenuItem,
this.phase3ToolStripMenuItem});
this.pPUClockToolStripMenuItem.Name = "pPUClockToolStripMenuItem";
this.pPUClockToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
this.pPUClockToolStripMenuItem.Text = "PPU Clock";
//
// phase0ToolStripMenuItem
//
this.phase0ToolStripMenuItem.Checked = true;
this.phase0ToolStripMenuItem.CheckOnClick = true;
this.phase0ToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.phase0ToolStripMenuItem.Name = "phase0ToolStripMenuItem";
this.phase0ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.phase0ToolStripMenuItem.Text = "Phase 0";
this.phase0ToolStripMenuItem.Click += new System.EventHandler(this.phase0ToolStripMenuItem_Click);
//
// phase1ToolStripMenuItem
//
this.phase1ToolStripMenuItem.CheckOnClick = true;
this.phase1ToolStripMenuItem.Name = "phase1ToolStripMenuItem";
this.phase1ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.phase1ToolStripMenuItem.Text = "Phase 1";
this.phase1ToolStripMenuItem.Click += new System.EventHandler(this.phase1ToolStripMenuItem_Click);
//
// phase2ToolStripMenuItem
//
this.phase2ToolStripMenuItem.CheckOnClick = true;
this.phase2ToolStripMenuItem.Name = "phase2ToolStripMenuItem";
this.phase2ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.phase2ToolStripMenuItem.Text = "Phase 2";
this.phase2ToolStripMenuItem.Click += new System.EventHandler(this.phase2ToolStripMenuItem_Click);
//
// phase3ToolStripMenuItem
//
this.phase3ToolStripMenuItem.CheckOnClick = true;
this.phase3ToolStripMenuItem.Name = "phase3ToolStripMenuItem";
this.phase3ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);
this.phase3ToolStripMenuItem.Text = "Phase 3";
this.phase3ToolStripMenuItem.Click += new System.EventHandler(this.phase3ToolStripMenuItem_Click);
//
// decodeNTSCSignalsToolStripMenuItem
//
this.decodeNTSCSignalsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.trueToolStripMenuItem,
this.showRawSignalsToolStripMenuItem,
this.falseToolStripMenuItem});
this.decodeNTSCSignalsToolStripMenuItem.Name = "decodeNTSCSignalsToolStripMenuItem";
this.decodeNTSCSignalsToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
this.decodeNTSCSignalsToolStripMenuItem.Text = "Decode NTSC Signals";
//
// trueToolStripMenuItem
//
this.trueToolStripMenuItem.Name = "trueToolStripMenuItem";
this.trueToolStripMenuItem.Size = new System.Drawing.Size(164, 22);
this.trueToolStripMenuItem.Text = "True";
this.trueToolStripMenuItem.Click += new System.EventHandler(this.trueToolStripMenuItem_Click);
//
// showRawSignalsToolStripMenuItem
//
this.showRawSignalsToolStripMenuItem.Name = "showRawSignalsToolStripMenuItem";
this.showRawSignalsToolStripMenuItem.Size = new System.Drawing.Size(164, 22);
this.showRawSignalsToolStripMenuItem.Text = "Show raw signals";
this.showRawSignalsToolStripMenuItem.Click += new System.EventHandler(this.showRawSignalsToolStripMenuItem_Click);
//
// falseToolStripMenuItem
//
this.falseToolStripMenuItem.Checked = true;
this.falseToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.falseToolStripMenuItem.Name = "falseToolStripMenuItem";
this.falseToolStripMenuItem.Size = new System.Drawing.Size(164, 22);
this.falseToolStripMenuItem.Text = "False";
this.falseToolStripMenuItem.Click += new System.EventHandler(this.falseToolStripMenuItem_Click);
//
// viewBoarderToolStripMenuItem
//
this.viewBoarderToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolstrip_ViewBorders_True,
this.toolstrip_ViewBorders_False});
this.viewBoarderToolStripMenuItem.Name = "viewBoarderToolStripMenuItem";
this.viewBoarderToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
this.viewBoarderToolStripMenuItem.Text = "View Border";
//
// toolstrip_ViewBorders_True
//
this.toolstrip_ViewBorders_True.Name = "toolstrip_ViewBorders_True";
this.toolstrip_ViewBorders_True.Size = new System.Drawing.Size(100, 22);
this.toolstrip_ViewBorders_True.Text = "True";
this.toolstrip_ViewBorders_True.Click += new System.EventHandler(this.trueToolStripMenuItem1_Click);
//
// toolstrip_ViewBorders_False
//
this.toolstrip_ViewBorders_False.Checked = true;
this.toolstrip_ViewBorders_False.CheckState = System.Windows.Forms.CheckState.Checked;
this.toolstrip_ViewBorders_False.Name = "toolstrip_ViewBorders_False";
this.toolstrip_ViewBorders_False.Size = new System.Drawing.Size(100, 22);
this.toolstrip_ViewBorders_False.Text = "False";
this.toolstrip_ViewBorders_False.Click += new System.EventHandler(this.falseToolStripMenuItem1_Click);
//
// viewScaleToolStripMenuItem
//
this.viewScaleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.xToolStripMenuItem,
this.xToolStripMenuItem1,
this.xToolStripMenuItem2,
this.xToolStripMenuItem3,
this.xToolStripMenuItem4,
this.xToolStripMenuItem5,
this.xToolStripMenuItem6,
this.xToolStripMenuItem7});
this.viewScaleToolStripMenuItem.Name = "viewScaleToolStripMenuItem";
this.viewScaleToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
this.viewScaleToolStripMenuItem.Text = "View Scale";
//
// xToolStripMenuItem
//
this.xToolStripMenuItem.Name = "xToolStripMenuItem";
this.xToolStripMenuItem.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem.Text = "1x";
this.xToolStripMenuItem.Click += new System.EventHandler(this.xToolStripMenuItem_Click);
//
// xToolStripMenuItem1
//
this.xToolStripMenuItem1.Name = "xToolStripMenuItem1";
this.xToolStripMenuItem1.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem1.Text = "2x";
this.xToolStripMenuItem1.Click += new System.EventHandler(this.xToolStripMenuItem1_Click);
//
// xToolStripMenuItem2
//
this.xToolStripMenuItem2.Name = "xToolStripMenuItem2";
this.xToolStripMenuItem2.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem2.Text = "3x";
this.xToolStripMenuItem2.Click += new System.EventHandler(this.xToolStripMenuItem2_Click);
//
// xToolStripMenuItem3
//
this.xToolStripMenuItem3.Name = "xToolStripMenuItem3";
this.xToolStripMenuItem3.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem3.Text = "4x";
this.xToolStripMenuItem3.Click += new System.EventHandler(this.xToolStripMenuItem3_Click);
//
// xToolStripMenuItem4
//
this.xToolStripMenuItem4.Name = "xToolStripMenuItem4";
this.xToolStripMenuItem4.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem4.Text = "5x";
this.xToolStripMenuItem4.Click += new System.EventHandler(this.xToolStripMenuItem4_Click);
//
// xToolStripMenuItem5
//
this.xToolStripMenuItem5.Name = "xToolStripMenuItem5";
this.xToolStripMenuItem5.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem5.Text = "6x";
this.xToolStripMenuItem5.Click += new System.EventHandler(this.xToolStripMenuItem5_Click);
//
// xToolStripMenuItem6
//
this.xToolStripMenuItem6.Name = "xToolStripMenuItem6";
this.xToolStripMenuItem6.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem6.Text = "7x";
this.xToolStripMenuItem6.Click += new System.EventHandler(this.xToolStripMenuItem6_Click);
//
// xToolStripMenuItem7
//
this.xToolStripMenuItem7.Name = "xToolStripMenuItem7";
this.xToolStripMenuItem7.Size = new System.Drawing.Size(86, 22);
this.xToolStripMenuItem7.Text = "8x";
this.xToolStripMenuItem7.Click += new System.EventHandler(this.xToolStripMenuItem7_Click);
//
// toolsToolStripMenuItem
//
this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.traceLoggerToolStripMenuItem,
this.nametableViewerToolStripMenuItem,
this.tASTimelineToolStripMenuItem,
this.hexEditorToolStripMenuItem});
this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20);
this.toolsToolStripMenuItem.Text = "Tools";
//
// traceLoggerToolStripMenuItem
//
this.traceLoggerToolStripMenuItem.Name = "traceLoggerToolStripMenuItem";
this.traceLoggerToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.traceLoggerToolStripMenuItem.Text = "TraceLogger";
this.traceLoggerToolStripMenuItem.Click += new System.EventHandler(this.traceLoggerToolStripMenuItem_Click);
//
// nametableViewerToolStripMenuItem
//
this.nametableViewerToolStripMenuItem.Name = "nametableViewerToolStripMenuItem";
this.nametableViewerToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.nametableViewerToolStripMenuItem.Text = "Nametable Viewer";
this.nametableViewerToolStripMenuItem.Click += new System.EventHandler(this.nametableViewerToolStripMenuItem_Click);
//
// tASTimelineToolStripMenuItem
//
this.tASTimelineToolStripMenuItem.Name = "tASTimelineToolStripMenuItem";
this.tASTimelineToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.tASTimelineToolStripMenuItem.Text = "TAS Timeline";
this.tASTimelineToolStripMenuItem.Click += new System.EventHandler(this.tASTimelineToolStripMenuItem_Click);
//
// pb_Screen
//
this.pb_Screen.AllowDrop = true;
this.pb_Screen.BackColor = System.Drawing.Color.Black;
this.pb_Screen.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
this.pb_Screen.Location = new System.Drawing.Point(0, 27);
this.pb_Screen.Name = "pb_Screen";
this.pb_Screen.Size = new System.Drawing.Size(256, 240);
this.pb_Screen.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pb_Screen.TabIndex = 1;
this.pb_Screen.TabStop = false;
//
// hexEditorToolStripMenuItem
//
this.hexEditorToolStripMenuItem.Name = "hexEditorToolStripMenuItem";
this.hexEditorToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.hexEditorToolStripMenuItem.Text = "Hex Editor";
this.hexEditorToolStripMenuItem.Click += new System.EventHandler(this.hexEditorToolStripMenuItem_Click);
//
// TriCNESGUI
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange;
this.ClientSize = new System.Drawing.Size(256, 267);
this.Controls.Add(this.pb_Screen);
this.Controls.Add(this.menuStrip1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.MainMenuStrip = this.menuStrip1;
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(272, 306);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(272, 306);
this.Name = "TriCNESGUI";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "TriCNES GUI";
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pb_Screen)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem consoleToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem tASToolStripMenuItem;
private PictureBoxWithInterpolationMode pb_Screen;
private System.Windows.Forms.ToolStripMenuItem loadROMToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem loadTASToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem load3ctToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem resetToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem powerCycleToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem screenshotToolStripMenuItem;
private ToolStripMenuItem settingsToolStripMenuItem;
private ToolStripMenuItem pPUClockToolStripMenuItem;
private ToolStripMenuItem phase0ToolStripMenuItem;
private ToolStripMenuItem phase1ToolStripMenuItem;
private ToolStripMenuItem phase2ToolStripMenuItem;
private ToolStripMenuItem phase3ToolStripMenuItem;
private ToolStripMenuItem decodeNTSCSignalsToolStripMenuItem;
private ToolStripMenuItem trueToolStripMenuItem;
private ToolStripMenuItem falseToolStripMenuItem;
private ToolStripMenuItem viewScaleToolStripMenuItem;
private ToolStripMenuItem xToolStripMenuItem;
private ToolStripMenuItem xToolStripMenuItem1;
private ToolStripMenuItem xToolStripMenuItem2;
private ToolStripMenuItem xToolStripMenuItem3;
private ToolStripMenuItem xToolStripMenuItem4;
private ToolStripMenuItem xToolStripMenuItem5;
private ToolStripMenuItem xToolStripMenuItem6;
private ToolStripMenuItem xToolStripMenuItem7;
private ToolStripMenuItem toolsToolStripMenuItem;
private ToolStripMenuItem traceLoggerToolStripMenuItem;
private ToolStripMenuItem viewBoarderToolStripMenuItem;
private ToolStripMenuItem toolstrip_ViewBorders_True;
private ToolStripMenuItem toolstrip_ViewBorders_False;
private ToolStripMenuItem nametableViewerToolStripMenuItem;
private ToolStripMenuItem showRawSignalsToolStripMenuItem;
private ToolStripMenuItem saveStateToolStripMenuItem;
private ToolStripMenuItem loadStateToolStripMenuItem;
private ToolStripMenuItem tASTimelineToolStripMenuItem;
private ToolStripMenuItem hexEditorToolStripMenuItem;
}
}
================================================
FILE: forms/TriCNESGUI.cs
================================================
using SDL2;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Input;
namespace TriCNES
{
public partial class TriCNESGUI : Form
{
// This is the the main window for a user to interact with this emulator.
// The logic for the emulator is contained entirely in a single C# file, for easy use importing it into other projects.
// this form here is intended to be used an an example.
// The intended use for this emulator is to run your own code specifically to collect data, but do with it as you please.
// Cheers! ~ Chris "100th_Coin" Siebert
public TriCNESGUI()
{
InitializeComponent();
pb_Screen.DragEnter += new DragEventHandler(pb_Screen_DragEnter);
pb_Screen.DragDrop += new DragEventHandler(pb_Screen_DragDrop);
FormClosing += new FormClosingEventHandler(TriCNESGUI_Closing);
SDL.SDL_Init(SDL.SDL_INIT_GAMECONTROLLER);
SDL.SDL_GameControllerEventState(SDL.SDL_ENABLE);
SDL.SDL_GameControllerUpdate();
int c = SDL.SDL_NumJoysticks();
if (c != 0)
{
joystickptr = SDL.SDL_JoystickOpen(0);
gameControllerPrt = SDL.SDL_GameControllerOpen(0);
}
}
IntPtr joystickptr;
IntPtr gameControllerPrt;
bool settings_ntsc;
bool settings_ntscRaw;
bool settings_border;
byte settings_alignment;
public Emulator EMU;
public Thread EmuClock;
string filePath;
bool FDS;
TASProperties TASPropertiesForm;
TASProperties3ct TASPropertiesForm3ct;
public TriCTraceLogger? TraceLogger;
public TriCNTViewer? NametableViewer;
public TriCTASTimeline? TasTimeline;
public TriCHexEditor? HexExditor;
void RunUpkeep()
{
if (PendingScreenshot)
{
PendingScreenshot = false;
if (EMU.PPU_DecodeSignal)
{
if (EMU.PPU_ShowScreenBorders)
{
Clipboard.SetImage(EMU.BorderedNTSCScreen.Bitmap);
}
else
{
Clipboard.SetImage(EMU.NTSCScreen.Bitmap);
}
}
else
{
if (EMU.PPU_ShowScreenBorders)
{
Clipboard.SetImage(EMU.BorderedScreen.Bitmap);
}
else
{
Clipboard.SetImage(EMU.Screen.Bitmap);
}
}
}
if (Pending_ShowScreenBorders)
{
Pending_ShowScreenBorders = false;
EMU.PPU_ShowScreenBorders = true;
BeginInvoke(new MethodInvoker(delegate () { ResizeWindow(ScreenMult); }));
}
if (Pending_HideScreenBorders)
{
Pending_HideScreenBorders = false;
EMU.PPU_ShowScreenBorders = false;
BeginInvoke(new MethodInvoker(delegate () { ResizeWindow(ScreenMult); }));
}
if (PendingSaveState)
{
PendingSaveState = false;
Savestate = EMU.SaveState();
}
if (PendingLoadState && Savestate != null && Savestate.Count > 0)
{
PendingLoadState = false;
EMU.LoadState(Savestate);
}
if (TraceLogger != null)
{
EMU.Logging = TraceLogger.Logging;
if (EMU.DebugLog == null)
{
EMU.DebugLog = new StringBuilder();
}
EMU.DebugRange_Low = TraceLogger.RangeLow;
EMU.DebugRange_High = TraceLogger.RangeHigh;
EMU.OnlyDebugInRange = TraceLogger.OnlyDebugInRange();
EMU.LoggingPPU = TraceLogger.LogPPUCycles();
}
else if(EMU.Logging)
{
EMU.Logging = false;
EMU.DebugLog = new StringBuilder();
}
if(HexExditor != null)
{
HexExditor.Update();
}
}
void RunPostFramePhase()
{
if (TraceLogger != null)
{
if (TraceLogger.Logging)
{
TraceLogger.Update();
if (TraceLogger.ClearEveryFrame())
{
EMU.DebugLog = new StringBuilder();
}
}
}
if (NametableViewer != null && !NametableViewer.IsDisposed)
{
RenderNametable();
NametableViewer.Update(NametableBitmap.Bitmap);
}
if (pb_Screen.InvokeRequired)
{
pb_Screen.BeginInvoke(new MethodInvoker(
delegate ()
{
if (EMU.PPU_DecodeSignal)
{
if (EMU.PPU_ShowScreenBorders)
{
pb_Screen.Image = EMU.BorderedNTSCScreen.Bitmap;
}
else
{
pb_Screen.Image = EMU.NTSCScreen.Bitmap;
}
}
else
{
if (EMU.PPU_ShowScreenBorders)
{
pb_Screen.Image = EMU.BorderedScreen.Bitmap;
}
else
{
pb_Screen.Image = EMU.Screen.Bitmap;
}
}
pb_Screen.Update();
}));
}
else
{
if (EMU.PPU_DecodeSignal)
{
if (EMU.PPU_ShowScreenBorders)
{
pb_Screen.Image = EMU.BorderedNTSCScreen.Bitmap;
}
else
{
pb_Screen.Image = EMU.NTSCScreen.Bitmap;
}
}
else
{
if (EMU.PPU_ShowScreenBorders)
{
pb_Screen.Image = EMU.BorderedScreen.Bitmap;
}
else
{
pb_Screen.Image = EMU.Screen.Bitmap;
}
}
pb_Screen.Update();
}
}
bool[] ControllerInputs()
{
bool[] joystickButtons = new bool[8];
int c = SDL.SDL_NumJoysticks();
if (c != 0)
{
SDL.SDL_GameControllerUpdate();
joystickButtons[0] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT) != 0;
joystickButtons[1] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT) != 0;
joystickButtons[2] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN) != 0;
joystickButtons[3] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP) != 0;
joystickButtons[4] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START) != 0;
joystickButtons[5] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK) != 0;
joystickButtons[6] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X) != 0;
joystickButtons[7] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A) != 0;
}
else
{
for (int i = 0; i < 8; i++)
{
joystickButtons[i] = false;
}
}
return joystickButtons;
}
byte RealtimeInputs()
{
bool[] joystickButtons = ControllerInputs();
byte controller1 = 0;
if (joystickButtons[7] || Keyboard.IsKeyDown(Key.X)) { controller1 |= 0x80; }
if (joystickButtons[6] || Keyboard.IsKeyDown(Key.Z)) { controller1 |= 0x40; }
if (joystickButtons[5] || Keyboard.IsKeyDown(Key.RightShift)) { controller1 |= 0x20; }
if (joystickButtons[4] || Keyboard.IsKeyDown(Key.Enter)) { controller1 |= 0x10; }
if (joystickButtons[3] || Keyboard.IsKeyDown(Key.Up)) { controller1 |= 0x08; }
if (joystickButtons[2] || Keyboard.IsKeyDown(Key.Down)) { controller1 |= 0x04; }
if (joystickButtons[1] || Keyboard.IsKeyDown(Key.Left)) { controller1 |= 0x02; }
if (joystickButtons[0] || Keyboard.IsKeyDown(Key.Right)) { controller1 |= 0x01; }
return controller1;
}
CancellationTokenSource cancel;
void ClockEmulator(CancellationToken ct)
{
int frameCount = 0;
while (!ct.IsCancellationRequested)
{
if (Form.ActiveForm != null)
{
if (Keyboard.IsKeyDown(Key.Q)) { PendingSaveState = true; }
if (Keyboard.IsKeyDown(Key.W)) { PendingLoadState = true; }
EMU.ControllerPort1 = RealtimeInputs();
}
RunUpkeep();
EMU._CoreFrameAdvance();
RunPostFramePhase();
frameCount++;
}
}
DirectBitmap NametableBitmap;
public Bitmap RenderNametable()
{
if (NametableBitmap != null)
{
NametableBitmap.Dispose();
}
NametableBitmap = new DirectBitmap(512, 480);
if (EMU.Cart == null)
{
return NametableBitmap.Bitmap;
}
int tx = 0;
int ty = 0;
int x = 0;
int y = 0;
int px = 0;
int py = 0;
int PatternTile;
int pal = 0;
bool ForceBackdropOnIndex0 = NametableViewer.UseBackdrop();
while (ty < 2)
{
while (tx < 2)
{
while (y < 30)
{
while (x < 32)
{
PatternTile = EMU.ObservePPU((ushort)(0x2000 + 0x400 * tx + 0x800 * ty + x + y * 32));
pal = EMU.ObservePPU((ushort)(0x2000 + 0x400 * (tx + 1) + 0x800 * ty - 0x40 + x / 4 + (y / 4) * 8));
if ((x & 3) >= 2)
{
pal = pal >> 2;
}
if ((y & 3) >= 2)
{
pal = pal >> 4;
}
pal = pal & 3;
while (py < 8)
{
while (px < 8)
{
int k = ((EMU.ObservePPU((ushort)(py + PatternTile * 16 + (!EMU.PPU_PatternSelect_Background ? 0 : 0x1000))) >> (7 - px)) & 1) + 2 * ((EMU.ObservePPU((ushort)(py + 8 + PatternTile * 16 + (!EMU.PPU_PatternSelect_Background ? 0 : 0x1000))) >> (7 - px)) & 1);
if (k == 0 && ForceBackdropOnIndex0)
{
k = EMU.ObservePPU(0x3F00);
}
else
{
k = EMU.ObservePPU((ushort)(0x3F00 + k + pal * 4));
}
int col = unchecked((int)Emulator.NesPalInts[k & 0x3F]);
NametableBitmap.SetPixel(tx * 0x100 + x * 8 + px, ty * 0xF0 + y * 8 + py, col);
px++;
}
px = 0;
py++;
}
py = 0;
x++;
}
x = 0;
y++;
}
y = 0;
tx++;
}
tx = 0;
ty++;
}
bool DrawScreenBoundary = NametableViewer.DrawBoundary();
if (DrawScreenBoundary)
{
// convert the t register into X,Y coordinates
/*
The v and t registers are 15 bits:
yyy NN YYYYY XXXXX
||| || ||||| +++++-- coarse X scroll
||| || +++++-------- coarse Y scroll
||| ++-------------- nametable select
+++----------------- fine Y scroll
*/
int X = ((EMU.PPU_t & 0b11111) << 3) | EMU.PPU_FineXScroll | ((EMU.PPU_t & 0b10000000000) >> 2);
int Y = ((EMU.PPU_t & 0b1111100000) >> 2) | ((EMU.PPU_t & 0b111000000000000) >> 12) | ((EMU.PPU_t & 0b100000000000) >> 4);
int i = 0;
while (i <= 257)
{
NametableBitmap.SetPixel((X + 511 + i) & 511, (Y + 479) % 480, Color.White);
NametableBitmap.SetPixel((X + 511 + i) & 511, (Y + 240) % 480, Color.White);
i++;
}
i = 0;
while (i <= 241)
{
NametableBitmap.SetPixel((X + 511) & 511, (Y + 479 + i) % 480, Color.White);
NametableBitmap.SetPixel((X + 256) & 511, (Y + 479 + i) % 480, Color.White);
i++;
}
}
if (NametableViewer.OverlayScreen())
{
int X = ((EMU.PPU_t & 0b11111) << 3) | EMU.PPU_FineXScroll | ((EMU.PPU_t & 0b10000000000) >> 2);
int Y = ((EMU.PPU_t & 0b1111100000) >> 2) | ((EMU.PPU_t & 0b111000000000000) >> 12) | ((EMU.PPU_t & 0b100000000000) >> 4);
for (int xx = 0; xx < 256; xx++)
{
for (int yy = 0; yy < 240; yy++)
{
NametableBitmap.SetPixel((X + xx) & 511, (Y + yy) % 480, EMU.Screen.GetPixel(xx, yy));
}
}
}
return NametableBitmap.Bitmap;
}
string fds_bios; // file path to the FDS bios if one is loaded.
public bool LoadROM(string FilePath)
{
if (FDS)
{
if (fds_bios == null || fds_bios.Length == 0)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"roms\"))
{
InitDirectory += @"roms\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Title = "Select FDS BIOS",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
fds_bios = ofd.FileName;
byte[] FDS_BIOS = File.ReadAllBytes(fds_bios);
if (FDS_BIOS.Length != 0x2000)
{
fds_bios = "";
return false;
}
}
else
{
return false;
}
}
Cartridge Cart = new Cartridge(filePath, fds_bios);
EMU.Cart = Cart;
Cart.Emu = EMU;
return true;
}
else
{
Cartridge Cart = new Cartridge(filePath);
EMU.Cart = Cart;
Cart.Emu = EMU;
return true;
}
return false;
}
public void InsertDisk(string filepath)
{
if(EMU.Cart.FDS != null)
{
EMU.Cart.FDS.InsertDisk(filepath);
}
}
void ClockEmulator3CT(CancellationToken ct)
{
Cartridge[] CartArray = TASPropertiesForm3ct.CartridgeArray;
int[] CyclesToSwapOn = TASPropertiesForm3ct.CyclesToSwapOn.ToArray();
int[] CartsToSwapIn = TASPropertiesForm3ct.CartsToSwapIn.ToArray();
EMU.Cart = CartArray[0];
int i = 1; // what cycle is being executed next?
int j = 0; // what step of the .3ct TAS is this?
while (j < CyclesToSwapOn.Length)
{
if (i == CyclesToSwapOn[j]) // if there's a cart swap on this cycle
{
EMU.Cart = CartArray[CartsToSwapIn[j]]; // swap the cartridge to the next one in the list
j++;
}
EMU._CoreCycleAdvance();
i++;
}
// once the .3ct TAS is completed, continue running the emulator with whatever cartridge is loaded last.
while (!ct.IsCancellationRequested)
{
RunUpkeep();
EMU._CoreFrameAdvance();
RunPostFramePhase();
}
}
private void loadROMToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"roms\"))
{
InitDirectory += @"roms\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Filter = "NES ROM files (*.nes)|*.nes",
Title = "Select file",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
filePath = ofd.FileName;
FDS = Path.GetExtension(ofd.FileName) == ".fds";
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
EMU.PPUClock = settings_alignment;
if (!LoadROM(filePath)) { return; }
cancel = new CancellationTokenSource();
EmuClock = new Thread(() => ClockEmulator(cancel.Token));
EmuClock.SetApartmentState(ApartmentState.STA);
EmuClock.IsBackground = true;
EmuClock.Start();
GC.Collect();
}
}
private void loadTASToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Filter =
"All TAS Files (.3c2, .3c3, .bk2, .tasproj, .fm2, .fm3, .fmv, .r08)|*.3c2;*.3c3;*.bk2;*.tasproj;*.fm2;*.fm3;*.fmv;*.r08" +
"|TriCNES TAS File (.3c2, .3c3)|*.3c2;*.3c3" +
"|Bizhawk Movie (.bk2)|*.bk2" +
"|Bizhawk TAStudio (.tasproj)|*.tasproj" +
"|FCEUX Movie (.fm2)|*.fm2" +
"|FCEUX TAS Editor (.fm3)|*.fm3" +
"|Famtastia Movie (.fmv)|*.fmv" +
"|Replay Device (.r08)|*.r08",
Title = "Select file",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
if (TASPropertiesForm != null)
{
TASPropertiesForm.Close();
TASPropertiesForm.Dispose();
}
TASPropertiesForm = new TASProperties();
TASPropertiesForm.TasFilePath = ofd.FileName;
TASPropertiesForm.MainGUI = this;
TASPropertiesForm.Init();
TASPropertiesForm.Show();
TASPropertiesForm.Location = Location;
}
}
public void StartTAS()
{
if (filePath == "" || filePath == null)
{
MessageBox.Show("You need to select a ROM before running a TAS.");
return;
}
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
if (!LoadROM(filePath)) { return; }
EMU.TAS_ReadingTAS = true;
EMU.TAS_InputLog = TASPropertiesForm.TasInputLog;
EMU.TAS_ResetLog = TASPropertiesForm.TasResetLog;
EMU.ClockFiltering = TASPropertiesForm.SubframeInputs();
EMU.PPUClock = TASPropertiesForm.GetPPUClockPhase();
EMU.CPUClock = TASPropertiesForm.GetCPUClockPhase();
EMU.TAS_InputSequenceIndex = 0;
switch (TASPropertiesForm.extension)
{
case ".bk2":
case ".tasproj":
{
int i = 0;
while (i < EMU.RAM.Length) //bizhawk RAM pattern
{
if ((i & 7) > 4)
{
EMU.RAM[i] = 0xFF;
}
else
{
EMU.RAM[i] = 0;
}
i++;
}
}
break;
case ".fm2":
case ".fm3":
{
if (TASPropertiesForm.UseFCEUXFrame0Timing())
{
// FCEUX incorrectly starts at the beginning of scanline 240, and cycle 0 is *after* the reset instruction.
// However, I think there's some other incorrect timing going on with FCEUX, and in order to sync TASes, I need to start at scanline 239, dot 312
EMU.PPU_Scanline = 239;
EMU.PPU_Dot = 312;
// but of course, by starting here, the VBlank flag will be incorrectly set early.
EMU.SyncFM2 = true; // so this bool prevents that.
EMU.TAS_InputSequenceIndex--; // since this runs an extra vblank, this needs to be offset by 1
}
else
{
EMU.TAS_InputSequenceIndex++;
EMU.PPU_Dot = 0;
}
// FCEUX also starts with this RAM pattern
int i = 0;
while (i < EMU.RAM.Length) //bizhawk RAM pattern
{
if ((i & 7) > 4)
{
EMU.RAM[i] = 0xFF;
}
else
{
EMU.RAM[i] = 0;
}
i++;
}
}
break;
case ".r08":
{
// This following comment block can be removed if you want to set up RAM for the Bad Apple TAS's .r08 file.
/*
string s = "0000000000000C000000000000000000E2000000001D1E000000000001000000984820BEFE68A8A5F7A6F8600000000010400000000000000000000000000000A2A58EFF07A216EA8EFD07020000000020200091318A11319131C8C430D0F14C40000000000000000101030000000000000000000000000000000000000000000000000000F000000000020000A0A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101000000000000000000000000000100000000000000000000000000000000000035000000008E002001008A4820BEFE68AA0C000000004C4000000001A804D9B4B4070004DAB4B4030004DBB4B4030005DCB4B4030004DDB4B4030004DEB4B4030004DFB4B4030004E0B4B4030004E1B4B4030004E2B4B4030004E3B4B4030004E4B4B4030004E5B4B4030004E6B4C886A080F5D000D00B00003F2FC7F8C8FE0024000F5200FB0400A9018D164085C04A8D1640AD16404A26C090F8A5C060A202206B0195C1CA10F8A000206B0191C2C8C4C190F6206B01F0E5206B0185C3206B0185C26CC200FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB003AFB00FB00FB00FB10D2A27DA07DF50400040004D93525D8F70000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8410000F8410000F8250000F8250000F8410000F8410000F8250000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000787A2021047F1918470000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F722CC891000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600A5";
int i = 0;
while (i < 0x800)
{
EMU.RAM[i] = byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
i++;
}
*/
break;
}
}
cancel = new CancellationTokenSource();
EmuClock = new Thread(() => ClockEmulator(cancel.Token));
EmuClock.SetApartmentState(ApartmentState.STA);
EmuClock.IsBackground = true;
EmuClock.Start();
GC.Collect();
}
public void Start3CTTAS()
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
EMU.Dispose();
}
if (TASPropertiesForm3ct.FromRESET())
{
if (EMU == null)
{
MessageBox.Show("The emulator needs to be powered on before running from RESET.");
return;
}
EMU.Reset();
}
else
{
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
EMU.PPUClock = settings_alignment;
}
foreach(Cartridge c in TASPropertiesForm3ct.CartridgeArray)
{
c.Emu = EMU;
}
cancel = new CancellationTokenSource();
EmuClock = new Thread(() => ClockEmulator3CT(cancel.Token));
EmuClock.IsBackground = true;
EmuClock.Start();
}
private void load3ctToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Filter =
"3CT TAS Files (.3ct)|*.3ct",
Title = "Select file",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
if (TASPropertiesForm3ct != null)
{
TASPropertiesForm3ct.Close();
TASPropertiesForm3ct.Dispose();
}
TASPropertiesForm3ct = new TASProperties3ct();
TASPropertiesForm3ct.TasFilePath = ofd.FileName;
TASPropertiesForm3ct.MainGUI = this;
TASPropertiesForm3ct.Init();
TASPropertiesForm3ct.Show();
TASPropertiesForm3ct.Location = Location;
}
}
private void resetToolStripMenuItem_Click(object sender, EventArgs e)
{
if (EMU != null)
{
EMU.Reset();
}
}
private void powerCycleToolStripMenuItem_Click(object sender, EventArgs e)
{
if (EMU != null)
{
Emulator Emu2 = new Emulator();
Emu2.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
Emu2.PPU_ShowScreenBorders = settings_border;
Emu2.PPUClock = settings_alignment;
Emu2.Cart = EMU.Cart;
Emu2.Cart.Emu = Emu2;
EMU = Emu2;
}
}
bool PendingScreenshot;
private void screenshotToolStripMenuItem_Click(object sender, EventArgs e)
{
PendingScreenshot = true;
}
private void pb_Screen_DragEnter(object sender, DragEventArgs e)
{
var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
if (Path.GetExtension(filenames[0]) == ".nes" || Path.GetExtension(filenames[0]) == ".NES" || Path.GetExtension(filenames[0]) == ".fds" || Path.GetExtension(filenames[0]) == ".FDS") e.Effect = DragDropEffects.All;
else e.Effect = DragDropEffects.None;
}
private void pb_Screen_DragDrop(object sender, DragEventArgs e)
{
var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
string filename = filenames[0];
filePath = filename;
bool prev_FDS = FDS;
FDS = Path.GetExtension(filePath).ToLower() == ".fds";
if (!FDS || !prev_FDS)
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
}
if (FDS && prev_FDS)
{
InsertDisk(filePath);
}
else
{
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
EMU.PPUClock = settings_alignment;
if (!LoadROM(filePath)) { return; }
cancel = new CancellationTokenSource();
EmuClock = new Thread(() => ClockEmulator(cancel.Token));
EmuClock.SetApartmentState(ApartmentState.STA);
EmuClock.IsBackground = true;
EmuClock.Start();
}
GC.Collect();
}
private void TriCNESGUI_Closing(Object sender, FormClosingEventArgs e)
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
if (TASPropertiesForm != null)
{
TASPropertiesForm.Dispose();
}
if (TASPropertiesForm3ct != null)
{
TASPropertiesForm3ct.Dispose();
}
if (TraceLogger != null)
{
TraceLogger.Dispose();
}
if (NametableViewer != null)
{
NametableViewer.Dispose();
}
if(TasTimeline != null)
{
TasTimeline.Dispose();
}
if (HexExditor != null)
{
HexExditor.Dispose();
}
Application.Exit();
}
private void phase0ToolStripMenuItem_Click(object sender, EventArgs e)
{
phase0ToolStripMenuItem.Checked = true;
phase1ToolStripMenuItem.Checked = false;
phase2ToolStripMenuItem.Checked = false;
phase3ToolStripMenuItem.Checked = false;
RebootWithAlignment(0);
}
private void phase1ToolStripMenuItem_Click(object sender, EventArgs e)
{
phase0ToolStripMenuItem.Checked = false;
phase1ToolStripMenuItem.Checked = true;
phase2ToolStripMenuItem.Checked = false;
phase3ToolStripMenuItem.Checked = false;
RebootWithAlignment(1);
}
private void phase2ToolStripMenuItem_Click(object sender, EventArgs e)
{
phase0ToolStripMenuItem.Checked = false;
phase1ToolStripMenuItem.Checked = false;
phase2ToolStripMenuItem.Checked = true;
phase3ToolStripMenuItem.Checked = false;
RebootWithAlignment(2);
}
private void phase3ToolStripMenuItem_Click(object sender, EventArgs e)
{
phase0ToolStripMenuItem.Checked = false;
phase1ToolStripMenuItem.Checked = false;
phase2ToolStripMenuItem.Checked = false;
phase3ToolStripMenuItem.Checked = true;
RebootWithAlignment(3);
}
private void RebootWithAlignment(byte Alignment)
{
if (EMU != null)
{
Emulator Emu2 = new Emulator();
Emu2.Cart = EMU.Cart;
Emu2.Cart.Emu = Emu2;
EMU = Emu2;
EMU.PPUClock = Alignment;
EMU.CPUClock = 0;
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
}
settings_alignment = Alignment;
}
private void trueToolStripMenuItem_Click(object sender, EventArgs e)
{
falseToolStripMenuItem.Checked = false;
showRawSignalsToolStripMenuItem.Checked = false;
trueToolStripMenuItem.Checked = true;
if (EMU != null)
{
EMU.PPU_DecodeSignal = true;
EMU.PPU_ShowRawNTSCSignal = false;
}
settings_ntsc = true;
settings_ntscRaw = false;
}
private void falseToolStripMenuItem_Click(object sender, EventArgs e)
{
trueToolStripMenuItem.Checked = false;
showRawSignalsToolStripMenuItem.Checked = false;
falseToolStripMenuItem.Checked = true;
if (EMU != null)
{
EMU.PPU_DecodeSignal = false;
EMU.PPU_ShowRawNTSCSignal = false;
}
settings_ntsc = false;
settings_ntscRaw = false;
}
private void showRawSignalsToolStripMenuItem_Click(object sender, EventArgs e)
{
trueToolStripMenuItem.Checked = false;
showRawSignalsToolStripMenuItem.Checked = true;
falseToolStripMenuItem.Checked = false;
if (EMU != null)
{
EMU.PPU_DecodeSignal = true;
EMU.PPU_ShowRawNTSCSignal = true;
}
settings_ntsc = true;
settings_ntscRaw = true;
}
public void ResizeWindow(int scale)
{
int w = 256;
int h = 240;
if (EMU != null)
{
if (EMU.PPU_ShowScreenBorders)
{
w = 341;
h = 262;
}
}
Size pbs = new Size();
pbs.Width = w * scale;
pbs.Height = h * scale;
Size ws = new Size();
ws.Width = w * scale + 16;
ws.Height = h * scale + 66;
MinimumSize = ws;
MaximumSize = ws;
pb_Screen.Size = pbs;
Width = ws.Width;
Height = ws.Height;
}
int ScreenMult = 1;
private void xToolStripMenuItem_Click(object sender, EventArgs e)
{
ScreenMult = 1;
ResizeWindow(1);
}
private void xToolStripMenuItem1_Click(object sender, EventArgs e)
{
ScreenMult = 2;
ResizeWindow(2);
}
private void xToolStripMenuItem2_Click(object sender, EventArgs e)
{
ScreenMult = 3;
ResizeWindow(3);
}
private void xToolStripMenuItem3_Click(object sender, EventArgs e)
{
ScreenMult = 4;
ResizeWindow(4);
}
private void xToolStripMenuItem4_Click(object sender, EventArgs e)
{
ScreenMult = 5;
ResizeWindow(5);
}
private void xToolStripMenuItem5_Click(object sender, EventArgs e)
{
ScreenMult = 6;
ResizeWindow(6);
}
private void xToolStripMenuItem6_Click(object sender, EventArgs e)
{
ScreenMult = 7;
ResizeWindow(7);
}
private void xToolStripMenuItem7_Click(object sender, EventArgs e)
{
ScreenMult = 8;
ResizeWindow(8);
}
private void traceLoggerToolStripMenuItem_Click(object sender, EventArgs e)
{
if(TraceLogger != null)
{
TraceLogger.Focus();
return;
}
TraceLogger = new TriCTraceLogger();
TraceLogger.MainGUI = this;
TraceLogger.Init();
TraceLogger.Show();
TraceLogger.Location = Location;
}
bool Pending_ShowScreenBorders;
private void trueToolStripMenuItem1_Click(object sender, EventArgs e)
{
toolstrip_ViewBorders_False.Checked = false;
toolstrip_ViewBorders_True.Checked = true;
if (EMU != null)
{
Pending_ShowScreenBorders = true;
}
settings_border = true;
}
bool Pending_HideScreenBorders;
private void falseToolStripMenuItem1_Click(object sender, EventArgs e)
{
toolstrip_ViewBorders_False.Checked = true;
toolstrip_ViewBorders_True.Checked = false;
if (EMU != null)
{
Pending_HideScreenBorders = true;
}
settings_border = false;
}
private void nametableViewerToolStripMenuItem_Click(object sender, EventArgs e)
{
if(NametableViewer != null)
{
NametableViewer.Focus();
return;
}
NametableViewer = new TriCNTViewer();
NametableViewer.MainGUI = this;
NametableViewer.Show();
NametableViewer.Location = Location;
}
private void hexEditorToolStripMenuItem_Click(object sender, EventArgs e)
{
if (HexExditor != null)
{
HexExditor.Focus();
return;
}
HexExditor = new TriCHexEditor();
HexExditor.MainGUI = this;
HexExditor.Show();
HexExditor.Location = Location;
}
List Savestate = new List();
bool PendingSaveState = false;
private void saveStateToolStripMenuItem_Click(object sender, EventArgs e)
{
PendingSaveState = true;
}
bool PendingLoadState = false;
private void loadStateToolStripMenuItem_Click(object sender, EventArgs e)
{
if (TasTimeline == null) // this would cause a desync otherwise, so forcefully prevent this.
{
PendingLoadState = true;
}
}
private void tASTimelineToolStripMenuItem_Click(object sender, EventArgs e)
{
if(TasTimeline != null)
{
TasTimeline.Focus();
return;
}
bool EMUExists = (EMU != null);
if (!EMUExists)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"roms\"))
{
InitDirectory += @"roms\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Filter = "NES ROM files (*.nes)|*.nes",
Title = "Select file",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
filePath = ofd.FileName;
FDS = Path.GetExtension(ofd.FileName) == ".fds";
TasTimeline = new TriCTASTimeline(this);
TasTimeline.Show();
TasTimeline.Location = Location;
}
}
else
{
TasTimeline = new TriCTASTimeline(this);
TasTimeline.Show();
TasTimeline.Location = Location;
}
}
public List ParseTasFile(string TasFilePath, out List Resets)
{
// determine file type
string extension = Path.GetExtension(TasFilePath);
// create list of inputs from the tas file, and make any settings changes if needed.
byte[] ByteArray = File.ReadAllBytes(TasFilePath);
List TASInputs = new List(); // Low byte is player 1, High byte is player 2.
List TASResets = new List();
switch (extension)
{
case ".bk2":
case ".tasproj":
{
// .bk2 files are actually just .zip files!
// Let's yoink "Input Log.txt" from this .bk2 file
StringReader InputLog = new StringReader(new string(new StreamReader(ZipFile.OpenRead(TasFilePath).Entries.Where(x => x.Name.Equals("Input Log.txt", StringComparison.InvariantCulture)).FirstOrDefault().Open(), Encoding.UTF8).ReadToEnd().ToArray()));
// now to parse the input log!
InputLog.ReadLine(); // "[Input]"
string key = InputLog.ReadLine(); // "LogKey: ... "
bool Bk2_Port1 = key.Contains("P1");
bool Bk2_Port2 = key.Contains("P2");
string ln = InputLog.ReadLine();
ushort u = 0;
while (ln != null && ln.Length > 3)
{
int pipeIndex = ln.Substring(1, ln.Length - 1).IndexOf('|') + 1;
char[] lnCharArray = ln.ToCharArray();
bool reset = lnCharArray[pipeIndex - 1] == 'r';
u = 0;
if (Bk2_Port1)
{
u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x08 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x04 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x02 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x01 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x10 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x20 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x40 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x80 : 0);
}
else if (Bk2_Port2) // Are there any NES TASes that only feature controller 2?
{
u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x0800 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x0400 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x0200 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x0100 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x1000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x2000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x4000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x8000 : 0);
}
if (Bk2_Port1 && Bk2_Port2)
{
pipeIndex = ln.Substring(pipeIndex + 1, ln.Length - 1 - pipeIndex).IndexOf('|') + pipeIndex + 1;
u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x0800 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x0400 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x0200 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x0100 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x1000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x2000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x4000 : 0);
u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x8000 : 0);
}
TASInputs.Add(u);
TASResets.Add(reset);
ln = InputLog.ReadLine();
if (ln == "[/Input]")
{
break;
}
}
}
break;
case ".fm2":
{
// change the alignment to use FCEUX's
// header info of varying size
// Every line of a header ends in $0A
// Every header section is named. Example: $0A "romFileName"
// Since the input log begins with "|" and none of the header section names begin with "|", I can assume $0A"|" is the start of the input log
bool fm2_UsePort0 = false;
bool fm2_UsePort1 = false;
int i = 0;
while (i < ByteArray.Length)
{
// parse for "port0 ?"
if (ByteArray[i] == 0x0A &&
ByteArray[i + 1] == 0x70 &&
ByteArray[i + 2] == 0x6F &&
ByteArray[i + 3] == 0x72 &&
ByteArray[i + 4] == 0x74 &&
ByteArray[i + 5] == 0x30 &&
ByteArray[i + 6] == 0x20
)
{
fm2_UsePort0 = ByteArray[i + 7] == 0x31;
}
// parse for "port1 ?"
if (ByteArray[i] == 0x0A &&
ByteArray[i + 1] == 0x70 &&
ByteArray[i + 2] == 0x6F &&
ByteArray[i + 3] == 0x72 &&
ByteArray[i + 4] == 0x74 &&
ByteArray[i + 5] == 0x31 &&
ByteArray[i + 6] == 0x20
)
{
fm2_UsePort1 = ByteArray[i + 7] == 0x31;
}
if (ByteArray[i] == 0x0A && ByteArray[i + 1] == 0x7C)
{
break;
}
i++;
}
ushort u = 0;
int Port0Index = 0;
int Port1Index = 0;
while (i < ByteArray.Length)
{
if (ByteArray[i] == 0x0A)
{
if (i == ByteArray.Length - 1)
{
break;
}
if (ByteArray[i + 1] == 0x0A)
{
// The .fm2 TAS file format supports empty rows. Formatting quirk?
i++;
continue;
}
if (ByteArray[i + 1] == 0x23)
{
// The .fm2 TAS file format supports comments, in the following format:
//\n### Comment
// so basically, check for `#` as the next character.
// And now we skip until the next new line.
i++;
continue;
}
bool reset = (ByteArray[i + 2] & 1) == 1;
if (fm2_UsePort0)
{
Port0Index = i + 4;
if (fm2_UsePort1)
{
Port1Index = i + 0xD;
}
}
else if (fm2_UsePort1)
{
Port1Index = i + 0x6;
}
u = 0;
if (fm2_UsePort0)
{
u |= (ushort)(ByteArray[Port0Index] == 0x2E ? 0 : 1);
u |= (ushort)(ByteArray[Port0Index + 1] == 0x2E ? 0 : 2);
u |= (ushort)(ByteArray[Port0Index + 2] == 0x2E ? 0 : 4);
u |= (ushort)(ByteArray[Port0Index + 3] == 0x2E ? 0 : 8);
u |= (ushort)(ByteArray[Port0Index + 4] == 0x2E ? 0 : 0x10);
u |= (ushort)(ByteArray[Port0Index + 5] == 0x2E ? 0 : 0x20);
u |= (ushort)(ByteArray[Port0Index + 6] == 0x2E ? 0 : 0x40);
u |= (ushort)(ByteArray[Port0Index + 7] == 0x2E ? 0 : 0x80);
}
if (fm2_UsePort1)
{
u |= (ushort)(ByteArray[Port1Index] == 0x2E ? 0 : 0x100);
u |= (ushort)(ByteArray[Port1Index + 1] == 0x2E ? 0 : 0x200);
u |= (ushort)(ByteArray[Port1Index + 2] == 0x2E ? 0 : 0x400);
u |= (ushort)(ByteArray[Port1Index + 3] == 0x2E ? 0 : 0x800);
u |= (ushort)(ByteArray[Port1Index + 4] == 0x2E ? 0 : 0x1000);
u |= (ushort)(ByteArray[Port1Index + 5] == 0x2E ? 0 : 0x2000);
u |= (ushort)(ByteArray[Port1Index + 6] == 0x2E ? 0 : 0x4000);
u |= (ushort)(ByteArray[Port1Index + 7] == 0x2E ? 0 : 0x8000);
}
TASInputs.Add(u);
TASResets.Add(reset);
}
i++;
}
}
break;
case ".fm3":
{
// similar to fm2, this has a header of varying length.
// But it also contains significantly more metadata after the input log.
// we need to parse $0A"length "
bool fm3_UsePort0 = false;
bool fm3_UsePort1 = false;
int i = 0;
while (i < ByteArray.Length)
{
if (ByteArray[i] == 0x0A)
{
if (ByteArray[i] == 0x0A &&
ByteArray[i + 1] == 0x70 &&
ByteArray[i + 2] == 0x6F &&
ByteArray[i + 3] == 0x72 &&
ByteArray[i + 4] == 0x74 &&
ByteArray[i + 5] == 0x30 &&
ByteArray[i + 6] == 0x20
)
{
fm3_UsePort0 = ByteArray[i + 7] == 0x31;
}
// parse for "port1 ?"
if (ByteArray[i] == 0x0A &&
ByteArray[i + 1] == 0x70 &&
ByteArray[i + 2] == 0x6F &&
ByteArray[i + 3] == 0x72 &&
ByteArray[i + 4] == 0x74 &&
ByteArray[i + 5] == 0x31 &&
ByteArray[i + 6] == 0x20
)
{
fm3_UsePort1 = ByteArray[i + 7] == 0x31;
}
// check if this is the header info for "length"
if (ByteArray[i] == 0x0A)
{
if (ByteArray[i + 1] == 0x6C &&
ByteArray[i + 2] == 0x65 &&
ByteArray[i + 3] == 0x6E &&
ByteArray[i + 4] == 0x67 &&
ByteArray[i + 5] == 0x74 &&
ByteArray[i + 6] == 0x68 &&
ByteArray[i + 7] == 0x20)
{
// okay, so the length is in ascii...
// let's figure out where the next $0A character is
int next0A = i + 8;
while (next0A < ByteArray.Length)
{
if (ByteArray[next0A] == 0x0A)
{
break;
}
next0A++;
}
// okay, so the string from i+8 though next0A is the length.
byte[] StringArray = new byte[next0A - (i + 8)];
Array.Copy(ByteArray, i + 8, StringArray, 0, StringArray.Length);
int InputLogLength = int.Parse(Encoding.Default.GetString(StringArray));
i = next0A + 2;
int tempMul = 1;
if (fm3_UsePort0) { tempMul++; }
if (fm3_UsePort1) { tempMul++; }
int InputLogByteLength = InputLogLength * tempMul;
// first byte is always zero?
// next byte is controller 1 (if enabled)
// next byte is controller 2 (if enabled)
ushort u = 0;
while (i < next0A + 2 + InputLogByteLength)
{
bool reset = (ByteArray[i] & 1) == 1;
i++;// dummy byte (?)
u = 0;
if (fm3_UsePort0) { u = ByteArray[i]; i++; }
if (fm3_UsePort1) { u |= (ushort)(ByteArray[i] << 8); i++; }
TASInputs.Add(u);
TASResets.Add(reset);
}
}
}
}
i++;
}
}
break;
case ".fmv":
{
int i = 0x90; // there's a 144 byte header
bool fmv_UseController2 = (ByteArray[5] & 0b00010000) != 0;
if (fmv_UseController2)
{
while (i < ByteArray.Length)
{
ushort u = (ushort)(FamtasiaInput2Standard(ByteArray[i]) | (FamtasiaInput2Standard(ByteArray[i + 1]) << 8));
TASInputs.Add(u);
i += 2;
}
}
else
{
while (i < ByteArray.Length)
{
TASInputs.Add(FamtasiaInput2Standard(ByteArray[i]));
i++;
}
}
}
break;
case ".3c2":
{
// The .3c2 format is pretty much identical to the .r08 file format, but with a 1-byte header.
// Bit 0: 0 = Latch Filtering. 1 = Clock Filtering.
// Bit 1: 0 = Only controller 1. 1 = Controller 1 and controller 2.
// Bit 2: 0 = No reset button. 1 = The reset button is used in this TAS.
bool UseController2 = (ByteArray[0] & 2) != 0;
bool UseReset = (ByteArray[0] & 4) != 0;
byte b = 0;
byte b2 = 0;
int i = 1;
while (i < ByteArray.Length)
{
b = ByteArray[i];
i++;
if (UseController2)
{
b2 = ByteArray[i];
i++;
}
TASInputs.Add((ushort)(b | (b2 << 8)));
if (UseReset)
{
bool res = (ByteArray[i] & 0x80) == 0x80; // I use bit 7 for the reset button. (bit 0 is for lag frames in the .3c3 format.)
TASResets.Add(res);
i++;
}
}
TASInputs.Add(0); // append a zero to the end for safe measure.
}
break;
case ".r08":
{
// the .r08 file format is conveniently already in the format I want for my emulator.
byte b = 0;
byte b2 = 0;
int i = 0;
while (i < ByteArray.Length)
{
b = ByteArray[i];
b2 = ByteArray[i + 1];
TASInputs.Add((ushort)(b | (b2 << 8)));
i += 2;
}
TASInputs.Add(0); // append a zero to the end for safe measure.
}
break;
case ".3c3":
{
// .3c3 is the format for my TAS timeline.
// The big differences are:
// - .3c3 saves the savestate information
// - .3c3 saves the "lag frame" information as well. (So every frame is 3 bytes now.)
// .3c3 has a 16 byte header.
// It's just little-endian 32-bit integers, and the same 1-byte header used in .3c2's.
// The first one determines how many bytes are in every savestate.
// the second one determinines how many frames there are in this TAS.
// I guess that means there's a limit of 2,147,483,647 frames in a .3c3 TAS file. God help me if I ever feel compelled to challenge this.
// Then there's a handful of unused bytes. ByteArray[15] is the same format as the 1-byte header used in 3c2's.
// Bit 0: 0 = Latch Filtering. 1 = Clock Filtering.
// Bit 1: 0 = Only controller 1. 1 = Controller 1 and controller 2.
// Bit 2: 0 = No reset button. 1 = The reset button is used in this TAS.
int SavestateLength = ByteArray[0] | (ByteArray[1] << 8) | (ByteArray[2] << 16) | (ByteArray[3] << 24);
int rerecords = ByteArray[4] | (ByteArray[5] << 8) | (ByteArray[6] << 16) | (ByteArray[7] << 24);
int frameCount = ByteArray[8] | (ByteArray[9] << 8) | (ByteArray[10] << 16) | (ByteArray[11] << 24);
bool UseController2 = (ByteArray[15] & 2) != 0;
bool UseReset = (ByteArray[15] & 4) != 0;
List> saveStates = new List>();
List> saveStates2 = new List>();
List lagFrames = new List();
byte b = 0;
byte b2 = 0;
int i = 16;
while (i < frameCount * 3 + 16)
{
b = ByteArray[i];
i++;
if (UseController2)
{
b2 = ByteArray[i];
i++;
}
TASInputs.Add((ushort)(b | (b2 << 8)));
bool lagframe = (ByteArray[i] & 1) == 1; // I use bit 0 for the lag frame info.
lagFrames.Add(lagframe);
if (UseReset)
{
bool res = (ByteArray[i] & 0x80) == 0x80; // I use bit 7 for the reset button.
TASResets.Add(res);
}
i++;
saveStates.Add(new List());
saveStates2.Add(new List());
}
// and from here until you reach the end of the file, the data is arranged in the following format:
// [32-bit int declaring the frame number, and 'n' bytes for the save state at that frame.]
while (i < ByteArray.Length)
{
// read the 4 byte header.
int frameIndex = ByteArray[i] | (ByteArray[i + 1] << 8) | (ByteArray[i + 2] << 16) | (ByteArray[i + 3] << 24);
i += 4;
int j = 0;
while (j < SavestateLength)
{
saveStates[frameIndex].Add(ByteArray[i]);
i++;
j++;
}
}
if (TasTimeline != null)
{
TriCTASTimeline.TimelineSavestates = saveStates;
TriCTASTimeline.TimelineTempSavestates = saveStates2; // the empty list.
TriCTASTimeline.LagFrames = lagFrames;
TasTimeline.highestFrameEmulatedEver = frameCount - 1;
TasTimeline.frameEmulated = frameCount - 1;
TasTimeline.Rerecords = rerecords;
}
}
break;
// TODO: ask if the .tasd file format is a thing yet
}
if (TASResets.Count == 0) // If not using Resets, we still want to initialize the Resets list, in case they are added to the TAS timeline at a later point.
{
TASResets = new List(new bool[TASInputs.Count]);
}
Resets = TASResets;
return TASInputs;
}
byte FamtasiaInput2Standard(byte input)
{
//famtasia format is SsABDULR
byte b0 = (byte)(input & 0x8);
byte b1 = (byte)(input & 0x4);
byte b2 = (byte)(input & 0xC0);
byte b3 = (byte)(input & 0x30);
b0 >>= 1;
b1 <<= 1;
byte b4 = (byte)(b2 & 0x80);
byte b5 = (byte)(b2 & 0x40);
b4 >>= 1;
b5 <<= 1;
b2 = (byte)(b4 | b5);
b2 >>= 2;
b3 <<= 2;
byte b = (byte)(b2 | b3 | b0 | b1 | (input & 0x3));
return b;
}
public void CreateTASTimelineEmulator()
{
if (EmuClock != null)
{
cancel.Cancel();
EmuClock.Join();
}
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
Timeline_Paused = true;
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
EMU.PPUClock = settings_alignment;
if (!LoadROM(filePath)) { return; }
cancel = new CancellationTokenSource();
EmuClock = new Thread(() => ClockTimelineEmulator(cancel.Token));
EmuClock.SetApartmentState(ApartmentState.STA);
EmuClock.IsBackground = true;
EmuClock.Start();
}
public bool Timeline_PendingPause;
public bool Timeline_PendingResume;
public bool Timeline_Paused;
public bool Timeline_PendingFrameAdvance;
public bool Timeline_PendingLoadState;
public int Timeline_PendingFrameNumber;
public bool Timeline_PendingHardReset;
public bool Timeline_PendingArbitrarySavestate;
public bool Timeline_AutoPlayUntilTarget;
public int Timeline_AutoPlayTarget;
public bool Timeline_PendingMouseDown;
public bool Timeline_PendingMouseHeld;
public bool Timeline_PendingResetScreen;
public bool Timeline_PendingClockFiltering;
public bool Timeline_HotkeyHeld_RShoulder;
public bool Timeline_HotkeyHeld_RTrigger;
public bool Timeline_HotkeyHeld_LTrigger;
public List Timeline_LoadState;
void ClockTimelineEmulator(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
if (Timeline_PendingHardReset)
{
Timeline_PendingHardReset = false;
if (EMU != null)
{
EMU.Dispose();
GC.Collect();
}
EMU = new Emulator();
EMU.PPU_DecodeSignal = settings_ntsc;
EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;
EMU.PPU_ShowScreenBorders = settings_border;
EMU.PPUClock = settings_alignment;
if (!LoadROM(filePath)) { return; }
if (Timeline_PendingClockFiltering)
{
Timeline_PendingClockFiltering = false;
EMU.TASTimelineClockFiltering = true;
}
}
if (Timeline_PendingArbitrarySavestate)
{
Timeline_PendingArbitrarySavestate = false; // pretty much only ever set when loading a TAS.
List state = EMU.SaveState();
TriCTASTimeline.TimelineSavestates.Add(state);
TriCTASTimeline.TimelineTempSavestates.Add(new List());
}
bool[] ControllerHotkeys = OtherControllerHotkeys();
if (!Timeline_HotkeyHeld_RShoulder && ControllerHotkeys[0])
{
Timeline_PendingPause = !Timeline_Paused;
Timeline_PendingResume = Timeline_Paused;
}
if ((ControllerHotkeys[2] && ControllerHotkeys[1]) || (!Timeline_HotkeyHeld_RTrigger && ControllerHotkeys[2]))
{
Timeline_PendingFrameAdvance = true;
Timeline_PendingPause = !Timeline_Paused;
}
bool rewinding = false;
if ((ControllerHotkeys[3] && ControllerHotkeys[1]) || (!Timeline_HotkeyHeld_LTrigger && ControllerHotkeys[3]))
{
TasTimeline.FrameRewind();
Timeline_PendingPause = !Timeline_Paused;
rewinding = true;
}
Timeline_HotkeyHeld_RShoulder = ControllerHotkeys[0];
Timeline_HotkeyHeld_RTrigger = ControllerHotkeys[2];
Timeline_HotkeyHeld_LTrigger = ControllerHotkeys[3];
if (Timeline_PendingPause)
{
Timeline_PendingPause = false;
Timeline_Paused = true;
TasTimeline.ChangePlayPauseButtonText("Paused");
}
if (Timeline_PendingResume)
{
Timeline_PendingResume = false;
Timeline_Paused = false;
TasTimeline.ChangePlayPauseButtonText("Running");
}
if (Timeline_PendingMouseDown)
{
Timeline_PendingMouseDown = false;
TasTimeline.TimelineMouseDownEvent();
}
if (Timeline_PendingMouseHeld)
{
Timeline_PendingMouseHeld = false;
TasTimeline.TimelineMouseHeldEvent();
}
if (Timeline_PendingLoadState)
{
Timeline_PendingLoadState = false;
PendingLoadState = true;
Savestate = Timeline_LoadState;
TasTimeline.frameIndex = Timeline_PendingFrameNumber;
}
if (Timeline_PendingResetScreen)
{
Timeline_PendingResetScreen = false;
pb_Screen.Invoke(new MethodInvoker(
delegate ()
{
Bitmap b = new Bitmap(pb_Screen.Image);
for (int x = 0; x < b.Width; x++) { for (int y = 0; y < b.Height; y++) { b.SetPixel(x, y, Color.Black); } }
pb_Screen.Image = b;
pb_Screen.Update();
}));
}
bool FrameAdvance = false;
if (Timeline_PendingFrameAdvance)
{
Timeline_PendingFrameAdvance = false;
FrameAdvance = true;
}
if (Timeline_AutoPlayUntilTarget && TasTimeline.frameIndex >= Timeline_AutoPlayTarget)
{
Timeline_AutoPlayUntilTarget = false;
}
RunUpkeep();
if (Timeline_Paused && !FrameAdvance && !Timeline_AutoPlayUntilTarget)
{
Thread.Sleep(50);
}
else
{
if (TasTimeline.frameIndex == TriCTASTimeline.TimelineSavestates.Count)
{
// create a savestate for the previous frame.
if (TasTimeline.SavestateEveryFrame())
{
List state = EMU.SaveState();
TriCTASTimeline.TimelineSavestates.Add(state);
TasTimeline.SavestateLength = state.Count;
}
else
{
List state = new List();
TriCTASTimeline.TimelineSavestates.Add(state);
}
if (TriCTASTimeline.TimelineSavestates[TasTimeline.frameIndex].Count > 0)
{
// if this savestate is not empty
List state = new List();
TriCTASTimeline.TimelineTempSavestates.Add(state);
TasTimeline.TrimTempSavestates();
//TriCTASTimeline.TEMPRerecordTracker.Add(TasTimeline.Rerecords);
}
else
{
// if this savestate is empty
List state = EMU.SaveState();
TriCTASTimeline.TimelineTempSavestates.Add(state);
TasTimeline.TrimTempSavestates();
//TriCTASTimeline.TEMPRerecordTracker.Add(TasTimeline.Rerecords);
}
}
else if (TasTimeline.frameIndex < TriCTASTimeline.TimelineTempSavestates.Count && TriCTASTimeline.TimelineTempSavestates[TasTimeline.frameIndex].Count == 0)
{
List state = EMU.SaveState();
TriCTASTimeline.TimelineTempSavestates[TasTimeline.frameIndex] = state;
TasTimeline.TrimTempSavestates();
}
if (TasTimeline.RecordInputs() && !rewinding)
{
byte realtimeInputs = RealtimeInputs();
if (TasTimeline.Player2())
{
EMU.ControllerPort2 = realtimeInputs;
EMU.ControllerPort1 = 0;
}
else
{
EMU.ControllerPort1 = realtimeInputs;
EMU.ControllerPort2 = 0;
}
ushort rimputs = (ushort)((EMU.ControllerPort2 << 8) | EMU.ControllerPort1);
TriCTASTimeline.Inputs[TasTimeline.frameIndex] = rimputs;
int row = TasTimeline.frameIndex - TasTimeline.TopFrame;
if (row >= 0 && row < 40)
{
TasTimeline.RecalculateTimelineRow(row, rimputs);
TasTimeline.RedrawTimelineRow(row, false);
}
if (TasTimeline.frameIndex < TasTimeline.frameEmulated)
{
TasTimeline.MarkStale(TasTimeline.frameIndex);
Timeline_PendingLoadState = false; // the MarkStale() function typically loads a savestate, but we don't want that here.
}
}
else
{
EMU.ControllerPort1 = (byte)(TriCTASTimeline.Inputs[TasTimeline.frameIndex] & 0xFF);
EMU.ControllerPort2 = (byte)((TriCTASTimeline.Inputs[TasTimeline.frameIndex] & 0xFF00) >> 8);
}
EMU._CoreFrameAdvance();
RunPostFramePhase();
if (TasTimeline.frameIndex < TriCTASTimeline.Resets.Count && TriCTASTimeline.Resets[TasTimeline.frameIndex])
{
EMU.Reset();
}
if (!EMU.TASTimelineClockFiltering || !EMU.LagFrame)
{
TasTimeline.FrameAdvance();
}
else
{
//Timeline_PendingFrameAdvance = true; // keep running until a non-lag frame.
}
}
}
}
public bool[] OtherControllerHotkeys()
{
bool[] joystickButtons = new bool[4];
int c = SDL.SDL_NumJoysticks();
if (c != 0)
{
SDL.SDL_GameControllerUpdate();
joystickButtons[0] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) != 0;
joystickButtons[1] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER) != 0;
joystickButtons[2] = SDL.SDL_GameControllerGetAxis(gameControllerPrt, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > 0.2;
joystickButtons[3] = SDL.SDL_GameControllerGetAxis(gameControllerPrt, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT) > 0.2;
}
else
{
for (int i = 0; i < 4; i++)
{
joystickButtons[i] = false;
}
}
return joystickButtons;
}
}
///
/// Inherits from PictureBox; adds Interpolation Mode Setting
///
public class PictureBoxWithInterpolationMode : PictureBox
{
public InterpolationMode InterpolationMode { get; set; }
public PictureBoxWithInterpolationMode()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
protected override void OnPaint(PaintEventArgs paintEventArgs)
{
paintEventArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
paintEventArgs.Graphics.InterpolationMode = InterpolationMode;
base.OnPaint(paintEventArgs);
}
}
}
================================================
FILE: forms/TriCNESGUI.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
17, 17
True
True
True
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TriCNTViewer.Designer.cs
================================================
namespace TriCNES
{
partial class TriCNTViewer
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCNTViewer));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.cb_ForcePal0ToBackdrop = new System.Windows.Forms.CheckBox();
this.cb_ScreenBoundary = new System.Windows.Forms.CheckBox();
this.cb_OverlayScreen = new System.Windows.Forms.CheckBox();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.screenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(0, 21);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(512, 480);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// cb_ForcePal0ToBackdrop
//
this.cb_ForcePal0ToBackdrop.AutoSize = true;
this.cb_ForcePal0ToBackdrop.Location = new System.Drawing.Point(13, 508);
this.cb_ForcePal0ToBackdrop.Name = "cb_ForcePal0ToBackdrop";
this.cb_ForcePal0ToBackdrop.Size = new System.Drawing.Size(121, 17);
this.cb_ForcePal0ToBackdrop.TabIndex = 1;
this.cb_ForcePal0ToBackdrop.Text = "Use Backdrop Color";
this.cb_ForcePal0ToBackdrop.UseVisualStyleBackColor = true;
//
// cb_ScreenBoundary
//
this.cb_ScreenBoundary.AutoSize = true;
this.cb_ScreenBoundary.Location = new System.Drawing.Point(12, 531);
this.cb_ScreenBoundary.Name = "cb_ScreenBoundary";
this.cb_ScreenBoundary.Size = new System.Drawing.Size(136, 17);
this.cb_ScreenBoundary.TabIndex = 2;
this.cb_ScreenBoundary.Text = "Draw Screen Boundary";
this.cb_ScreenBoundary.UseVisualStyleBackColor = true;
//
// cb_OverlayScreen
//
this.cb_OverlayScreen.AutoSize = true;
this.cb_OverlayScreen.Location = new System.Drawing.Point(12, 554);
this.cb_OverlayScreen.Name = "cb_OverlayScreen";
this.cb_OverlayScreen.Size = new System.Drawing.Size(99, 17);
this.cb_OverlayScreen.TabIndex = 3;
this.cb_OverlayScreen.Text = "Overlay Screen";
this.cb_OverlayScreen.UseVisualStyleBackColor = true;
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.fileToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(512, 24);
this.menuStrip1.TabIndex = 4;
this.menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.screenshotToolStripMenuItem});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
//
// screenshotToolStripMenuItem
//
this.screenshotToolStripMenuItem.Name = "screenshotToolStripMenuItem";
this.screenshotToolStripMenuItem.Size = new System.Drawing.Size(132, 22);
this.screenshotToolStripMenuItem.Text = "Screenshot";
this.screenshotToolStripMenuItem.Click += new System.EventHandler(this.screenshotToolStripMenuItem_Click);
//
// TriCNTViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(512, 579);
this.Controls.Add(this.cb_OverlayScreen);
this.Controls.Add(this.cb_ScreenBoundary);
this.Controls.Add(this.cb_ForcePal0ToBackdrop);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.menuStrip1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1;
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(528, 618);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(528, 618);
this.Name = "TriCNTViewer";
this.Text = "Nametable Viewer";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.CheckBox cb_ForcePal0ToBackdrop;
private System.Windows.Forms.CheckBox cb_ScreenBoundary;
private System.Windows.Forms.CheckBox cb_OverlayScreen;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem screenshotToolStripMenuItem;
}
}
================================================
FILE: forms/TriCNTViewer.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TriCNES
{
public partial class TriCNTViewer : Form
{
public TriCNESGUI MainGUI;
public TriCNTViewer()
{
InitializeComponent();
FormClosing += new FormClosingEventHandler(TriCNTViewer_Closing);
}
private void TriCNTViewer_Closing(Object sender, FormClosingEventArgs e)
{
MainGUI.NametableViewer = null;
this.Dispose();
}
public void Update(Bitmap b)
{
MethodInvoker upd = delegate
{
pictureBox1.Image = b;
pictureBox1.Update();
};
try
{
this.Invoke(upd);
}
catch (Exception e)
{
}
}
public bool UseBackdrop()
{
return cb_ForcePal0ToBackdrop.Checked;
}
public bool DrawBoundary()
{
return cb_ScreenBoundary.Checked;
}
public bool OverlayScreen()
{
return cb_OverlayScreen.Checked;
}
private void screenshotToolStripMenuItem_Click(object sender, EventArgs e)
{
Clipboard.SetImage(pictureBox1.Image);
}
}
}
================================================
FILE: forms/TriCNTViewer.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
17, 17
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TriCTASTimeline.Designer.cs
================================================
using System.Windows.Forms;
namespace TriCNES
{
partial class TriCTASTimeline
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCTASTimeline));
this.pb_Timeline = new System.Windows.Forms.PictureBox();
this.timelineScrollbar = new System.Windows.Forms.VScrollBar();
this.b_FrameAdvance = new System.Windows.Forms.Button();
this.b_FrameBack = new System.Windows.Forms.Button();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.tASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.loadTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveWithSavestatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exportTor08ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cellFrequencyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.perVBlankToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.perControllerStrobeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.b_play = new System.Windows.Forms.Button();
this.contextMenuStrip_Timeline = new System.Windows.Forms.ContextMenuStrip(this.components);
this.deleteFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.insertFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.truncateMovieToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.savestateThisFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.b_JumptoCursor = new System.Windows.Forms.Button();
this.cb_FollowCursor = new System.Windows.Forms.CheckBox();
this.tb_FollowDistance = new System.Windows.Forms.TrackBar();
this.cb_SavestateEveryFrame = new System.Windows.Forms.CheckBox();
this.tb_TempSavestates = new System.Windows.Forms.TextBox();
this.label_TempSavestates = new System.Windows.Forms.Label();
this.Tooltip_ = new System.Windows.Forms.ToolTip(this.components);
this.label_AutoSavestateThreshold = new System.Windows.Forms.Label();
this.tb_AutoSavestateThreshold = new System.Windows.Forms.TextBox();
this.cb_RecordInputs = new System.Windows.Forms.CheckBox();
this.cb_player2 = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.pb_Timeline)).BeginInit();
this.menuStrip1.SuspendLayout();
this.contextMenuStrip_Timeline.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.tb_FollowDistance)).BeginInit();
this.SuspendLayout();
//
// pb_Timeline
//
this.pb_Timeline.Location = new System.Drawing.Point(12, 27);
this.pb_Timeline.Name = "pb_Timeline";
this.pb_Timeline.Size = new System.Drawing.Size(353, 657);
this.pb_Timeline.TabIndex = 7;
this.pb_Timeline.TabStop = false;
//
// timelineScrollbar
//
this.timelineScrollbar.Location = new System.Drawing.Point(372, 27);
this.timelineScrollbar.Name = "timelineScrollbar";
this.timelineScrollbar.Size = new System.Drawing.Size(19, 657);
this.timelineScrollbar.TabIndex = 2;
//
// b_FrameAdvance
//
this.b_FrameAdvance.Location = new System.Drawing.Point(601, 38);
this.b_FrameAdvance.Name = "b_FrameAdvance";
this.b_FrameAdvance.Size = new System.Drawing.Size(75, 23);
this.b_FrameAdvance.TabIndex = 1;
this.b_FrameAdvance.Text = ">";
this.b_FrameAdvance.UseVisualStyleBackColor = true;
this.b_FrameAdvance.Click += new System.EventHandler(this.b_FrameAdvance_Click);
//
// b_FrameBack
//
this.b_FrameBack.Location = new System.Drawing.Point(439, 38);
this.b_FrameBack.Name = "b_FrameBack";
this.b_FrameBack.Size = new System.Drawing.Size(75, 23);
this.b_FrameBack.TabIndex = 2;
this.b_FrameBack.Text = "<";
this.b_FrameBack.UseVisualStyleBackColor = true;
this.b_FrameBack.Click += new System.EventHandler(this.b_FrameBack_Click);
//
// menuStrip1
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.tASToolStripMenuItem,
this.settingsToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(745, 24);
this.menuStrip1.TabIndex = 3;
this.menuStrip1.Text = "menuStrip1";
//
// tASToolStripMenuItem
//
this.tASToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.loadTASToolStripMenuItem,
this.saveTASToolStripMenuItem,
this.saveWithSavestatesToolStripMenuItem,
this.exportTor08ToolStripMenuItem});
this.tASToolStripMenuItem.Name = "tASToolStripMenuItem";
this.tASToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.tASToolStripMenuItem.Text = "File";
//
// loadTASToolStripMenuItem
//
this.loadTASToolStripMenuItem.Name = "loadTASToolStripMenuItem";
this.loadTASToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.loadTASToolStripMenuItem.Text = "Load";
this.loadTASToolStripMenuItem.Click += new System.EventHandler(this.loadTASToolStripMenuItem_Click);
//
// saveTASToolStripMenuItem
//
this.saveTASToolStripMenuItem.Name = "saveTASToolStripMenuItem";
this.saveTASToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.saveTASToolStripMenuItem.Text = "Save";
this.saveTASToolStripMenuItem.Click += new System.EventHandler(this.saveTASToolStripMenuItem_Click);
//
// saveWithSavestatesToolStripMenuItem
//
this.saveWithSavestatesToolStripMenuItem.Name = "saveWithSavestatesToolStripMenuItem";
this.saveWithSavestatesToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.saveWithSavestatesToolStripMenuItem.Text = "Save with savestates";
this.saveWithSavestatesToolStripMenuItem.Click += new System.EventHandler(this.saveWithSavestatesToolStripMenuItem_Click);
//
// exportTor08ToolStripMenuItem
//
this.exportTor08ToolStripMenuItem.Name = "exportTor08ToolStripMenuItem";
this.exportTor08ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.exportTor08ToolStripMenuItem.Text = "Export to .r08";
this.exportTor08ToolStripMenuItem.Click += new System.EventHandler(this.exportTor08ToolStripMenuItem_Click);
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.cellFrequencyToolStripMenuItem});
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
this.settingsToolStripMenuItem.Text = "Settings";
//
// cellFrequencyToolStripMenuItem
//
this.cellFrequencyToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.perVBlankToolStripMenuItem,
this.perControllerStrobeToolStripMenuItem});
this.cellFrequencyToolStripMenuItem.Name = "cellFrequencyToolStripMenuItem";
this.cellFrequencyToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.cellFrequencyToolStripMenuItem.Text = "Cell Frequency";
//
// perVBlankToolStripMenuItem
//
this.perVBlankToolStripMenuItem.Checked = true;
this.perVBlankToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.perVBlankToolStripMenuItem.Name = "perVBlankToolStripMenuItem";
this.perVBlankToolStripMenuItem.Size = new System.Drawing.Size(184, 22);
this.perVBlankToolStripMenuItem.Text = "Per VBlank";
this.perVBlankToolStripMenuItem.Click += new System.EventHandler(this.perVBlankToolStripMenuItem_Click);
//
// perControllerStrobeToolStripMenuItem
//
this.perControllerStrobeToolStripMenuItem.Name = "perControllerStrobeToolStripMenuItem";
this.perControllerStrobeToolStripMenuItem.Size = new System.Drawing.Size(184, 22);
this.perControllerStrobeToolStripMenuItem.Text = "Per Controller Strobe";
this.perControllerStrobeToolStripMenuItem.Click += new System.EventHandler(this.perControllerStrobeToolStripMenuItem_Click);
//
// b_play
//
this.b_play.Location = new System.Drawing.Point(521, 38);
this.b_play.Name = "b_play";
this.b_play.Size = new System.Drawing.Size(75, 23);
this.b_play.TabIndex = 4;
this.b_play.Text = "Paused";
this.b_play.UseVisualStyleBackColor = true;
this.b_play.Click += new System.EventHandler(this.b_play_Click);
//
// contextMenuStrip_Timeline
//
this.contextMenuStrip_Timeline.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.deleteFrameToolStripMenuItem,
this.insertFrameToolStripMenuItem,
this.truncateMovieToolStripMenuItem,
this.savestateThisFrameToolStripMenuItem});
this.contextMenuStrip_Timeline.Name = "contextMenuStrip_Timeline";
this.contextMenuStrip_Timeline.Size = new System.Drawing.Size(184, 92);
//
// deleteFrameToolStripMenuItem
//
this.deleteFrameToolStripMenuItem.Name = "deleteFrameToolStripMenuItem";
this.deleteFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
this.deleteFrameToolStripMenuItem.Text = "Delete Frame";
this.deleteFrameToolStripMenuItem.Click += new System.EventHandler(this.deleteFrameToolStripMenuItem_Click);
//
// insertFrameToolStripMenuItem
//
this.insertFrameToolStripMenuItem.Name = "insertFrameToolStripMenuItem";
this.insertFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
this.insertFrameToolStripMenuItem.Text = "Insert Frame";
this.insertFrameToolStripMenuItem.Click += new System.EventHandler(this.insertFrameToolStripMenuItem_Click);
//
// truncateMovieToolStripMenuItem
//
this.truncateMovieToolStripMenuItem.Name = "truncateMovieToolStripMenuItem";
this.truncateMovieToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
this.truncateMovieToolStripMenuItem.Text = "Truncate Movie";
this.truncateMovieToolStripMenuItem.Click += new System.EventHandler(this.truncateMovieToolStripMenuItem_Click);
//
// savestateThisFrameToolStripMenuItem
//
this.savestateThisFrameToolStripMenuItem.Name = "savestateThisFrameToolStripMenuItem";
this.savestateThisFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
this.savestateThisFrameToolStripMenuItem.Text = "Savestate This Frame";
this.savestateThisFrameToolStripMenuItem.Click += new System.EventHandler(this.savestateThisFrameToolStripMenuItem_Click);
//
// b_JumptoCursor
//
this.b_JumptoCursor.Location = new System.Drawing.Point(236, 699);
this.b_JumptoCursor.Name = "b_JumptoCursor";
this.b_JumptoCursor.Size = new System.Drawing.Size(99, 23);
this.b_JumptoCursor.TabIndex = 5;
this.b_JumptoCursor.Text = "Jump to Cursor";
this.b_JumptoCursor.UseVisualStyleBackColor = true;
this.b_JumptoCursor.Click += new System.EventHandler(this.b_JumptoCursor_Click);
//
// cb_FollowCursor
//
this.cb_FollowCursor.AutoSize = true;
this.cb_FollowCursor.Checked = true;
this.cb_FollowCursor.CheckState = System.Windows.Forms.CheckState.Checked;
this.cb_FollowCursor.Location = new System.Drawing.Point(26, 703);
this.cb_FollowCursor.Name = "cb_FollowCursor";
this.cb_FollowCursor.Size = new System.Drawing.Size(89, 17);
this.cb_FollowCursor.TabIndex = 6;
this.cb_FollowCursor.Text = "Follow Cursor";
this.cb_FollowCursor.UseVisualStyleBackColor = true;
//
// tb_FollowDistance
//
this.tb_FollowDistance.LargeChange = 1;
this.tb_FollowDistance.Location = new System.Drawing.Point(118, 699);
this.tb_FollowDistance.Maximum = 39;
this.tb_FollowDistance.Name = "tb_FollowDistance";
this.tb_FollowDistance.Size = new System.Drawing.Size(104, 45);
this.tb_FollowDistance.TabIndex = 8;
this.tb_FollowDistance.Value = 20;
this.tb_FollowDistance.Scroll += new System.EventHandler(this.tb_FollowDistance_Scroll);
//
// cb_SavestateEveryFrame
//
this.cb_SavestateEveryFrame.AutoSize = true;
this.cb_SavestateEveryFrame.Location = new System.Drawing.Point(409, 112);
this.cb_SavestateEveryFrame.Name = "cb_SavestateEveryFrame";
this.cb_SavestateEveryFrame.Size = new System.Drawing.Size(136, 17);
this.cb_SavestateEveryFrame.TabIndex = 9;
this.cb_SavestateEveryFrame.Text = "Savestate Every Frame";
this.cb_SavestateEveryFrame.UseVisualStyleBackColor = true;
//
// tb_TempSavestates
//
this.tb_TempSavestates.Location = new System.Drawing.Point(410, 132);
this.tb_TempSavestates.MaxLength = 5;
this.tb_TempSavestates.Name = "tb_TempSavestates";
this.tb_TempSavestates.Size = new System.Drawing.Size(41, 20);
this.tb_TempSavestates.TabIndex = 10;
this.tb_TempSavestates.Text = "120";
this.Tooltip_.SetToolTip(this.tb_TempSavestates, resources.GetString("tb_TempSavestates.ToolTip"));
this.tb_TempSavestates.TextChanged += new System.EventHandler(this.tb_TempSavestates_TextChanged);
this.tb_TempSavestates.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tb_FilterForNumbers);
//
// label_TempSavestates
//
this.label_TempSavestates.AutoSize = true;
this.label_TempSavestates.Location = new System.Drawing.Point(457, 139);
this.label_TempSavestates.Name = "label_TempSavestates";
this.label_TempSavestates.Size = new System.Drawing.Size(139, 13);
this.label_TempSavestates.TabIndex = 11;
this.label_TempSavestates.Text = "Temporary Savestate Count";
this.Tooltip_.SetToolTip(this.label_TempSavestates, resources.GetString("label_TempSavestates.ToolTip"));
//
// Tooltip_
//
this.Tooltip_.AutoPopDelay = 500000;
this.Tooltip_.InitialDelay = 500;
this.Tooltip_.ReshowDelay = 100;
//
// label_AutoSavestateThreshold
//
this.label_AutoSavestateThreshold.AutoSize = true;
this.label_AutoSavestateThreshold.Location = new System.Drawing.Point(457, 165);
this.label_AutoSavestateThreshold.Name = "label_AutoSavestateThreshold";
this.label_AutoSavestateThreshold.Size = new System.Drawing.Size(130, 13);
this.label_AutoSavestateThreshold.TabIndex = 13;
this.label_AutoSavestateThreshold.Text = "Auto-Savestate Threshold";
this.Tooltip_.SetToolTip(this.label_AutoSavestateThreshold, "Automatically make a savestate every \'n\' frames.\r\nA larger value will consume les" +
"s RAM, but leave gaps that will need to be re-emulated when loading earlier fram" +
"es.\r\n");
//
// tb_AutoSavestateThreshold
//
this.tb_AutoSavestateThreshold.Location = new System.Drawing.Point(410, 158);
this.tb_AutoSavestateThreshold.MaxLength = 5;
this.tb_AutoSavestateThreshold.Name = "tb_AutoSavestateThreshold";
this.tb_AutoSavestateThreshold.Size = new System.Drawing.Size(41, 20);
this.tb_AutoSavestateThreshold.TabIndex = 12;
this.tb_AutoSavestateThreshold.Text = "500";
this.Tooltip_.SetToolTip(this.tb_AutoSavestateThreshold, "Automatically make a savestate every \'n\' frames.\r\nA larger value will consume les" +
"s RAM, but leave gaps that will need to be re-emulated when loading earlier fram" +
"es.");
this.tb_AutoSavestateThreshold.TextChanged += new System.EventHandler(this.tb_AutoSavestateThreshold_TextChanged);
this.tb_AutoSavestateThreshold.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tb_FilterForNumbers);
//
// cb_RecordInputs
//
this.cb_RecordInputs.AutoSize = true;
this.cb_RecordInputs.Location = new System.Drawing.Point(409, 89);
this.cb_RecordInputs.Name = "cb_RecordInputs";
this.cb_RecordInputs.Size = new System.Drawing.Size(93, 17);
this.cb_RecordInputs.TabIndex = 14;
this.cb_RecordInputs.Text = "Record Inputs";
this.Tooltip_.SetToolTip(this.cb_RecordInputs, "If checked, the inputs you provide will be recorded on the timeline.\r\nThis will o" +
"verwrite older frames if you rewind.");
this.cb_RecordInputs.UseVisualStyleBackColor = true;
//
// cb_player2
//
this.cb_player2.AutoSize = true;
this.cb_player2.Location = new System.Drawing.Point(508, 89);
this.cb_player2.Name = "cb_player2";
this.cb_player2.Size = new System.Drawing.Size(64, 17);
this.cb_player2.TabIndex = 15;
this.cb_player2.Text = "Player 2";
this.Tooltip_.SetToolTip(this.cb_player2, "If checked, the inputs you provide will be recorded on the timeline.\r\nThis will o" +
"verwrite older frames if you rewind.");
this.cb_player2.UseVisualStyleBackColor = true;
//
// TriCTASTimeline
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(745, 743);
this.Controls.Add(this.cb_player2);
this.Controls.Add(this.cb_RecordInputs);
this.Controls.Add(this.label_AutoSavestateThreshold);
this.Controls.Add(this.tb_AutoSavestateThreshold);
this.Controls.Add(this.label_TempSavestates);
this.Controls.Add(this.tb_TempSavestates);
this.Controls.Add(this.cb_SavestateEveryFrame);
this.Controls.Add(this.tb_FollowDistance);
this.Controls.Add(this.timelineScrollbar);
this.Controls.Add(this.pb_Timeline);
this.Controls.Add(this.cb_FollowCursor);
this.Controls.Add(this.b_JumptoCursor);
this.Controls.Add(this.b_play);
this.Controls.Add(this.menuStrip1);
this.Controls.Add(this.b_FrameBack);
this.Controls.Add(this.b_FrameAdvance);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "TriCTASTimeline";
this.Text = "TAS Timeline";
((System.ComponentModel.ISupportInitialize)(this.pb_Timeline)).EndInit();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.contextMenuStrip_Timeline.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.tb_FollowDistance)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button b_FrameAdvance;
private System.Windows.Forms.VScrollBar timelineScrollbar;
private System.Windows.Forms.Button b_FrameBack;
private System.Windows.Forms.MenuStrip menuStrip1;
private System.Windows.Forms.ToolStripMenuItem tASToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem loadTASToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem saveTASToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportTor08ToolStripMenuItem;
private System.Windows.Forms.Button b_play;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip_Timeline;
private System.Windows.Forms.ToolStripMenuItem deleteFrameToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem insertFrameToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem truncateMovieToolStripMenuItem;
private System.Windows.Forms.Button b_JumptoCursor;
private System.Windows.Forms.CheckBox cb_FollowCursor;
private System.Windows.Forms.PictureBox pb_Timeline;
private System.Windows.Forms.TrackBar tb_FollowDistance;
private System.Windows.Forms.ToolStripMenuItem savestateThisFrameToolStripMenuItem;
private System.Windows.Forms.CheckBox cb_SavestateEveryFrame;
private System.Windows.Forms.TextBox tb_TempSavestates;
private System.Windows.Forms.Label label_TempSavestates;
private System.Windows.Forms.ToolTip Tooltip_;
private System.Windows.Forms.Label label_AutoSavestateThreshold;
private System.Windows.Forms.TextBox tb_AutoSavestateThreshold;
private System.Windows.Forms.ToolStripMenuItem saveWithSavestatesToolStripMenuItem;
private CheckBox cb_RecordInputs;
private ToolStripMenuItem cellFrequencyToolStripMenuItem;
private ToolStripMenuItem perVBlankToolStripMenuItem;
private ToolStripMenuItem perControllerStrobeToolStripMenuItem;
private CheckBox cb_player2;
}
}
================================================
FILE: forms/TriCTASTimeline.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Timers;
using System.Windows.Forms;
using static System.Windows.Forms.AxHost;
namespace TriCNES
{
public partial class TriCTASTimeline : Form
{
public Font Font_Consolas;
public Brush Brush_LeftColumn;
public Brush Brush_LeftColumn_Saved;
public Brush Brush_LeftColumn_TempSaved;
public Brush Brush_HighlightedCell;
public Brush Brush_WhiteCellP1;
public Brush Brush_WhiteCellP2;
public Brush Brush_GreenCellP1;
public Brush Brush_GreenCellP2;
public Brush Brush_GreenCellP1_Stale;
public Brush Brush_GreenCellP2_Stale;
public Brush Brush_RedCellP1;
public Brush Brush_RedCellP2;
public Brush Brush_RedCellP1_Stale;
public Brush Brush_RedCellP2_Stale;
struct Vector2
{
public int x;
public int y;
public Vector2(int X, int Y)
{
x = X;
y = Y;
}
public override string ToString()
{
return x.ToString() + ", " + y.ToString();
}
}
public struct TimelineCell
{
public bool Checked;
public bool LagFrame;
public bool Stale;
public bool Emulated;
public TimelineCell(bool t)
{
Checked = false;
LagFrame = false;
Stale = false;
Emulated = false;
}
}
public int SavestateLength;
public int Rerecords;
public TriCTASTimeline(TriCNESGUI Maingui)
{
MainGUI = Maingui;
InitializeComponent();
Font_Consolas = new Font("Consolas", 8);
Brush_LeftColumn = new SolidBrush(Color.LightGray);
Brush_LeftColumn_Saved = new SolidBrush(Color.Wheat);
Brush_LeftColumn_TempSaved = new SolidBrush(Color.LemonChiffon);
Brush_HighlightedCell = new SolidBrush(Color.LightBlue);
Brush_WhiteCellP1 = new SolidBrush(Color.WhiteSmoke);
Brush_WhiteCellP2 = new SolidBrush(Color.FromArgb(255, 230, 230, 230));
Brush_GreenCellP1 = new SolidBrush(Color.FromArgb(255, 200, 240, 200));
Brush_GreenCellP2 = new SolidBrush(Color.FromArgb(255, 190, 232, 190));
Brush_GreenCellP1_Stale = new SolidBrush(Color.FromArgb(255, 205, 220, 205));
Brush_GreenCellP2_Stale = new SolidBrush(Color.FromArgb(255, 195, 215, 195));
Brush_RedCellP1 = new SolidBrush(Color.FromArgb(255, 240, 200, 200));
Brush_RedCellP2 = new SolidBrush(Color.FromArgb(255, 232, 190, 190));
Brush_RedCellP1_Stale = new SolidBrush(Color.FromArgb(255, 220, 205, 205));
Brush_RedCellP2_Stale = new SolidBrush(Color.FromArgb(255, 215, 195, 195));
Inputs = new List();
Start();
Inputs.Add(0);
Resets.Add(false);
timelineBitmap = new Bitmap(80 + 16 * 17 + 1, 41 * 16 + 1);
G = Graphics.FromImage(timelineBitmap);
pb_Timeline.Image = timelineBitmap;
pb_Timeline.MouseDown += mouseDownEvent;
pb_Timeline.MouseUp += mouseUpEvent;
pb_Timeline.ContextMenuStrip = contextMenuStrip_Timeline;
pb_Timeline.MouseWheel += mouseWheelEvent;
timelineScrollbar.ValueChanged += timelineScrollbar_ValueChanged;
//loop timer
loopTimer = new System.Timers.Timer();
loopTimer.Interval = 50;// interval in milliseconds
loopTimer.Enabled = false;
loopTimer.Elapsed += loopTimerEvent;
loopTimer.AutoReset = true;
autosave = new System.Timers.Timer();
autosave.Interval = 60000;
autosave.Elapsed += autosaveEvent;
autosave.AutoReset = true;
autosave.Enabled = true;
Shown += TriCTASTimeline_Shown;
}
private void mouseWheelEvent(object sender, MouseEventArgs e)
{
int result = timelineScrollbar.Value - Math.Sign(e.Delta);
if (result > timelineScrollbar.Maximum - timelineScrollbar.LargeChange + 1)
{
result = timelineScrollbar.Maximum - timelineScrollbar.LargeChange + 1;
}
else if (result < 0)
{
result = 0;
}
timelineScrollbar.Value = result;
}
void TriCTASTimeline_Shown(object sender, EventArgs e)
{
RefreshTopOfTimeline();
}
void RefreshTopOfTimeline()
{
Rectangle[] GridOverlay = new Rectangle[]
{
new Rectangle(0,0,80,16),
new Rectangle(80 + 16*0,0,16,16),
new Rectangle(80 + 16*1,0,16,16),
new Rectangle(80 + 16*2,0,16,16),
new Rectangle(80 + 16*3,0,16,16),
new Rectangle(80 + 16*4,0,16,16),
new Rectangle(80 + 16*5,0,16,16),
new Rectangle(80 + 16*6,0,16,16),
new Rectangle(80 + 16*7,0,16,16),
new Rectangle(80 + 16*8,0,16,16),
new Rectangle(80 + 16*9,0,16,16),
new Rectangle(80 + 16*10,0,16,16),
new Rectangle(80 + 16*11,0,16,16),
new Rectangle(80 + 16*12,0,16,16),
new Rectangle(80 + 16*13,0,16,16),
new Rectangle(80 + 16*14,0,16,16),
new Rectangle(80 + 16*15,0,16,16),
new Rectangle(80 + 16*16,0,16,16)
};
G.FillRectangle(Brush_LeftColumn, new Rectangle(0, 0, 80 + 16 * 17, 16));
G.DrawRectangles(Pens.Black, GridOverlay);
G.DrawString(ClockFiltering ? "Input #" : "Frame #", Font_Consolas, Brushes.Black, 0, 0);
G.DrawString("A", Font_Consolas, Brushes.Black, 80 + 16 * 0, 0);
G.DrawString("B", Font_Consolas, Brushes.Black, 80 + 16 * 1, 0);
G.DrawString("s", Font_Consolas, Brushes.Black, 80 + 16 * 2, 0);
G.DrawString("S", Font_Consolas, Brushes.Black, 80 + 16 * 3, 0);
G.DrawString("U", Font_Consolas, Brushes.Black, 80 + 16 * 4, 0);
G.DrawString("D", Font_Consolas, Brushes.Black, 80 + 16 * 5, 0);
G.DrawString("L", Font_Consolas, Brushes.Black, 80 + 16 * 6, 0);
G.DrawString("R", Font_Consolas, Brushes.Black, 80 + 16 * 7, 0);
G.DrawString("A", Font_Consolas, Brushes.Black, 80 + 16 * 8, 0);
G.DrawString("B", Font_Consolas, Brushes.Black, 80 + 16 * 9, 0);
G.DrawString("s", Font_Consolas, Brushes.Black, 80 + 16 * 10, 0);
G.DrawString("S", Font_Consolas, Brushes.Black, 80 + 16 * 11, 0);
G.DrawString("U", Font_Consolas, Brushes.Black, 80 + 16 * 12, 0);
G.DrawString("D", Font_Consolas, Brushes.Black, 80 + 16 * 13, 0);
G.DrawString("L", Font_Consolas, Brushes.Black, 80 + 16 * 14, 0);
G.DrawString("R", Font_Consolas, Brushes.Black, 80 + 16 * 15, 0);
G.DrawString("r", Font_Consolas, Brushes.Black, 80 + 16 * 16, 0);
RefreshTimeline();
}
public Graphics G;
public Bitmap timelineBitmap;
private static System.Timers.Timer loopTimer;
private static System.Timers.Timer autosave;
private void loopTimerEvent(Object source, ElapsedEventArgs e)
{
//this does whatever you want to happen while clicking on the button
MainGUI.Timeline_PendingMouseHeld = true;
}
private void autosaveEvent(Object source, ElapsedEventArgs e)
{
if (Inputs.Count > 1000)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
InitDirectory += "autosave.3c2";
FileStream fs = File.OpenWrite(InitDirectory);
for (int i = 0; i < Inputs.Count; i++)
{
fs.WriteByte((byte)Inputs[i]);
fs.WriteByte((byte)(Inputs[i] >> 8));
}
fs.Close();
}
}
public void TimelineMouseHeldEvent()
{
MethodInvoker upd = delegate
{
int mouseX = MousePosition.X - Left - pb_Timeline.Left - 8;
int mouseY = MousePosition.Y - Top - pb_Timeline.Top - 48;
int Column = mouseX >= 80 ? (mouseX - 80) / 16 : -1;
if (Column > 15) { Column = 15; }
int Row = mouseY >= 0 ? mouseY / 16 : -1;
if (Row > 39) { Row = 39; }
Vector2 mousePos = new Vector2(Column, Row);
if (mouseHeld_initPos.y >= 0)
{
if (mouseHeld_initPos.x >= 0)
{
// we clicked on a cell
int spos = Math.Min(mousePos.y, mouseHeld_initPos.y);
int tpos = Math.Max(mousePos.y, mouseHeld_initPos.y);
if (spos < 0)
{
spos = 0;
}
for (int i = spos; i <= tpos; i++)
{
if (mouseHeld_initPos.x == 16)
{
TimelineGrid[i][17].Checked = mouseHeld_setInput;
RedrawTimelineRow(i, false);
int frame = i + TopFrame;
while (frame >= Inputs.Count)
{
Inputs.Add(0);
Resets.Add(false);
}
if (Inputs.Count + 39 > timelineScrollbar.Maximum)
{
timelineScrollbar.Maximum = Inputs.Count + 38;
}
Resets[frame] = mouseHeld_setInput;
}
else
{
bool state = GetCellInputStatus(new Vector2(mouseHeld_initPos.x, i));
if (state != mouseHeld_setInput)
{
ushort input = SetCellInputStatus(new Vector2(mouseHeld_initPos.x, i), mouseHeld_setInput);
TimelineGrid[i][mouseHeld_initPos.x + 1].Checked = mouseHeld_setInput;
RecalculateTimelineRow(i, input);
RedrawTimelineRow(i, false);
}
}
}
int checkStale = spos + TopFrame;
if (checkStale < frameEmulated)
{
MarkStale(checkStale);
}
}
else
{
// we clicked on the frame number.
}
}
};
this.Invoke(upd);
}
public int TopFrame = 0;
Vector2 mouseHeld_initPos;
bool mouseHeld_setInput;
private void mouseDownEvent(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
return;
}
loopTimer.Enabled = true;
int mouseX = MousePosition.X - Left - pb_Timeline.Left - 8;
int mouseY = MousePosition.Y - Top - pb_Timeline.Top - 48;
int Column = mouseX >= 80 ? (mouseX - 80) / 16 : -1;
if (Column > 16) { Column = 16; }
int Row = mouseY >= 0 ? mouseY / 16 : -1;
if (Row > 39) { Row = 39; }
mouseHeld_initPos = new Vector2(Column, Row);
MainGUI.Timeline_PendingMouseDown = true;
}
public void TimelineMouseDownEvent()
{
MethodInvoker upd = delegate
{
if (mouseHeld_initPos.y >= 0)
{
if (mouseHeld_initPos.x >= 0)
{
// we clicked on a cell
mouseHeld_setInput = !GetCellInputStatus(mouseHeld_initPos);
int frameClicked = TopFrame + mouseHeld_initPos.y;
if (mouseHeld_initPos.x == 16)
{
TimelineGrid[mouseHeld_initPos.y][17].Checked = mouseHeld_setInput;
RedrawTimelineRow(mouseHeld_initPos.y, false);
while (frameClicked >= Inputs.Count)
{
Inputs.Add(0);
Resets.Add(false);
}
if (Inputs.Count + 39 > timelineScrollbar.Maximum)
{
timelineScrollbar.Maximum = Inputs.Count + 38;
}
Resets[frameClicked] = mouseHeld_setInput;
}
else
{
// calculate if that cell had an input or not.
ushort input = SetCellInputStatus(mouseHeld_initPos, mouseHeld_setInput);
TimelineGrid[mouseHeld_initPos.y][mouseHeld_initPos.x + 1].Checked = mouseHeld_setInput;
RecalculateTimelineRow(mouseHeld_initPos.y, input);
RedrawTimelineRow(mouseHeld_initPos.y, false);
}
if (frameClicked < frameEmulated)
{
MarkStale(frameClicked);
}
}
else
{
// we clicked on the frame number.
// TODO: Move the cursor to this frame.
// - If there exists a savestate for this frame, then simply laod it.
// - Otherwise, we haven't seen this frame yet. Load the last savestate in the list, then emulate to this frame.
int frameClicked = TopFrame + mouseHeld_initPos.y;
if (frameClicked == frameIndex)
{
return; // we're already on that frame!
}
if (frameClicked < frameEmulated && (TimelineSavestates[frameClicked].Count == SavestateLength || TimelineTempSavestates[frameClicked].Count == SavestateLength))
{
int prevrow = frameIndex - TopFrame;
frameIndex = frameClicked - 1; // and we're good to go.
if (frameIndex == -1)
{
frameIndex = 0;
MainGUI.Timeline_LoadState = TimelineSavestates[0];
MainGUI.Timeline_PendingLoadState = true;
MainGUI.Timeline_PendingFrameNumber = 0;
UpdateTimelineRowStatus(prevrow);
RedrawTimelineRow(prevrow, false);
UpdateTimelineRowStatus(0);
RedrawTimelineRow(0, false);
MainGUI.Timeline_PendingResetScreen = true;
}
else
{
MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex
MainGUI.Timeline_PendingLoadState = true;
MainGUI.Timeline_PendingFrameNumber = frameIndex;
MainGUI.Timeline_PendingFrameAdvance = true;
UpdateTimelineRowStatus(prevrow);
RedrawTimelineRow(prevrow, false);
}
}
else
{
int row = frameIndex - TopFrame;
int prevFrame = frameIndex;
frameIndex = frameClicked;
if (frameIndex > frameEmulated)
{
frameIndex = frameEmulated;
}
UpdateTimelineRowStatus(row);
RedrawTimelineRow(row, false);
if (frameIndex < 0)
{
frameIndex = 0;
}
else
{
bool Unneeded = false;
MainGUI.Timeline_LoadState = GrabMostRecentSavestate(prevFrame, out Unneeded); // This function updates frameIndex
if (!Unneeded)
{
MainGUI.Timeline_PendingLoadState = true;
MainGUI.Timeline_PendingFrameNumber = frameIndex;
}
}
// Now we need to emulate all the way until we reach the target frame.
MainGUI.Timeline_AutoPlayUntilTarget = true;
MainGUI.Timeline_AutoPlayTarget = frameClicked;
row = frameIndex - TopFrame;
UpdateTimelineRowStatus(row);
RedrawTimelineRow(row, false);
if (frameIndex > frameEmulated)
{
frameEmulated = frameIndex;
}
if (frameIndex > highestFrameEmulatedEver)
{
highestFrameEmulatedEver = frameIndex;
}
while (frameIndex >= Inputs.Count)
{
Inputs.Add(0);
Resets.Add(false);
}
if (Inputs.Count + 39 > timelineScrollbar.Maximum)
{
timelineScrollbar.Maximum = Inputs.Count + 38;
}
}
}
}
};
this.Invoke(upd); // Use delegates here because this could otherwise modify the state of the timeline mid-rendering the timeline. (causing runtime errors)
}
public void MarkStale(int Frame)
{
frameEmulated = Frame; // mark everything after this as "stale"
if (frameIndex >= Frame)
{
Rerecords++;
frameIndex = Frame;
TimelineSavestates.RemoveRange(frameIndex + 1, TimelineSavestates.Count - (frameIndex + 1));
TimelineTempSavestates.RemoveRange(frameIndex + 1, TimelineTempSavestates.Count - (frameIndex + 1));
//TEMPRerecordTracker.RemoveRange(frameIndex + 1, TEMPRerecordTracker.Count - (frameIndex + 1));
MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex
System.GC.Collect();
MainGUI.Timeline_PendingLoadState = true;
MainGUI.Timeline_PendingFrameNumber = frameIndex;
}
RefreshTimeline();
}
private void mouseUpEvent(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
return;
}
loopTimer.Enabled = false;
}
bool GetCellInputStatus(Vector2 pos)
{
if (pos.x < 0 || pos.y < 0)
{
return false; // should never happen
}
int frame = pos.y + TopFrame;
// get frame index
if (frame >= Inputs.Count)
{
return false;
}
if (pos.x == 16)
{
return Resets[frame];
}
int shift = (7 - (pos.x & 7)) | (pos.x & 8);
return ((Inputs[frame] >> shift) & 1) == 1;
}
ushort SetCellInputStatus(Vector2 pos, bool state)
{
if (pos.x < 0 || pos.y < 0)
{
return 0; // should never happen
}
// get frame index
int frame = pos.y + TopFrame;
int shift = (7 - (pos.x & 7)) | (pos.x & 8);
int prevInputs = Inputs.Count;
while (frame >= Inputs.Count)
{
// Add new inputs until you reach this frame
if (state)
{
//Inputs.Add((ushort)(1 << shift));
Inputs.Add(0);
Resets.Add(false);
}
else
{
Inputs.Add(0);
Resets.Add(false);
}
}
if ((Inputs.Count > prevInputs))
{
timelineScrollbar.Maximum = Inputs.Count + 38;
}
if (state)
{
Inputs[frame] |= (ushort)(1 << shift);
}
else
{
Inputs[frame] &= (ushort)(0xFFFF ^ (1 << shift));
}
return Inputs[frame];
}
public TriCNESGUI MainGUI;
public static List LagFrames;
public static List TimelineGrid;
public static List> TimelineSavestates;
public static List> TimelineTempSavestates;
public static List TEMPRerecordTracker;
public static List Resets;
public static List Inputs; // high byte = controller 2
public int frameIndex;
public int highestFrameEmulatedEver; // highest emulated frame
public int frameEmulated; // highest emulated frame for the purposes of tracking stale frames
int AutoSavestateThreshold = 500;
int TempSavestates = 120;
public void Start()
{
TimelineGrid = new List();
TimelineSavestates = new List>();
TimelineTempSavestates = new List>();
LagFrames = new List();
Resets = new List();
//TEMPRerecordTracker = new List();
for (int i = 0; i < 40; i++)
{
TimelineCell[] t = new TimelineCell[18];
for (int j = 0; j < t.Length; j++)
{
t[0] = new TimelineCell(false);
}
TimelineGrid.Add(t);
}
Rerecords = 0;
frameIndex = 0;
timelineScrollbar.Maximum = Inputs.Count + 38;
timelineScrollbar.LargeChange = 40;
MainGUI.CreateTASTimelineEmulator();
List state = MainGUI.EMU.SaveState();
TimelineSavestates.Add(state);
TimelineTempSavestates.Add(new List());
SavestateLength = state.Count;
//TEMPRerecordTracker.Add(Rerecords);
}
int ScrollbarValue = 0;
private void timelineScrollbar_ValueChanged(object sender, EventArgs e)
{
TopFrame = timelineScrollbar.Value;
if (TopFrame != ScrollbarValue)
{
ScrollbarValue = TopFrame;
RefreshTimeline();
}
}
private void b_FrameAdvance_Click(object sender, EventArgs e)
{
MainGUI.Timeline_PendingFrameAdvance = true;
}
private void b_FrameBack_Click(object sender, EventArgs e)
{
FrameRewind();
}
public void FrameRewind()
{
int row = frameIndex - TopFrame;
int rowm1 = row - 1;
frameIndex -= 2;
if (frameIndex < 0)
{
frameIndex = 0;
}
UpdateTimelineRowStatus(row);
RedrawTimelineRow(row, false);
MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex
MainGUI.Timeline_PendingLoadState = true;
MainGUI.Timeline_PendingFrameNumber = frameIndex;
if (frameIndex == 0)
{
UpdateTimelineRowStatus(0);
RedrawTimelineRow(0, false);
MainGUI.Timeline_PendingResetScreen = true;
}
else
{
MainGUI.Timeline_PendingFrameNumber = frameIndex;
MainGUI.Timeline_PendingFrameAdvance = true;
}
if (frameIndex != rowm1)
{
MainGUI.Timeline_AutoPlayUntilTarget = true;
MainGUI.Timeline_AutoPlayTarget = rowm1;
}
}
public void FrameAdvance()
{
frameIndex++;
if (frameIndex > LagFrames.Count)
{
LagFrames.Add(MainGUI.EMU.LagFrame);
}
else
{
LagFrames[frameIndex - 1] = MainGUI.EMU.LagFrame;
}
if (frameIndex > Resets.Count)
{
Resets.Add(false);
}
if (frameIndex > frameEmulated)
{
frameEmulated = frameIndex;
}
if (frameIndex > highestFrameEmulatedEver)
{
highestFrameEmulatedEver = frameIndex;
}
if (frameIndex == TimelineSavestates.Count)
{
// create a savestate for the previous frame.
if (cb_SavestateEveryFrame.Checked || frameIndex % AutoSavestateThreshold == 0)
{
List state = MainGUI.EMU.SaveState();
TimelineSavestates.Add(state);
}
else
{
List state = new List();
TimelineSavestates.Add(state);
}
if (TimelineSavestates[frameIndex].Count > 0)
{
// if this savestate is not empty
List state = new List();
TimelineTempSavestates.Add(state);
}
else
{
// if this savestate is empty
List state = MainGUI.EMU.SaveState();
TimelineTempSavestates.Add(state);
}
//TEMPRerecordTracker.Add(Rerecords);
}
else if (TimelineSavestates[frameIndex].Count != SavestateLength && cb_SavestateEveryFrame.Checked)
{
List state = MainGUI.EMU.SaveState();
TimelineSavestates[frameIndex] = state;
//TEMPRerecordTracker[frameIndex] = Rerecords;
}
TrimTempSavestates();
while (frameIndex >= Inputs.Count)
{
Inputs.Add(0);
Resets.Add(false);
MethodInvoker upd = delegate
{
timelineScrollbar.Maximum = Inputs.Count + 38;
};
this.BeginInvoke(upd);
}
int row = frameIndex - TopFrame;
bool didFullRefresh = false;
if (cb_FollowCursor.Checked)
{
if (row >= TimelineGrid.Count || row > FollowDistance)
{
TopFrame = frameIndex - FollowDistance;
if (TopFrame != ScrollbarValue && TopFrame >= 0)
{
didFullRefresh = true;
RefreshTimeline();
MethodInvoker upd = delegate
{
ScrollbarValue = TopFrame;
timelineScrollbar.Value = TopFrame;
};
this.Invoke(upd);
}
}
}
if (!didFullRefresh)
{
UpdateTimelineRowStatus(row - 1);
RedrawTimelineRow(row - 1, false);
UpdateTimelineRowStatus(row);
RedrawTimelineRow(row, false);
}
}
private void loadTASToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
OpenFileDialog ofd = new OpenFileDialog()
{
FileName = "",
Filter =
"TriCNES TAS File (.3c2, .3c3)|*.3c2;*.3c3" +
"|Bizhawk Movie (.bk2)|*.bk2" +
"|Bizhawk TAStudio (.tasproj)|*.tasproj" +
"|FCEUX Movie (.fm2)|*.fm2" +
"|FCEUX TAS Editor (.fm3)|*.fm3" +
"|Famtastia Movie (.fmv)|*.fmv" +
"|Replay Device (.r08)|*.r08" +
"|All TAS Files (.3c2, .3c3, .bk2, .tasproj, .fm2, .fm3, .fmv, .r08)|*.3c2;*.3c3;*.bk2;*.tasproj;*.fm2;*.fm3;*.fmv;*.r08",
Title = "Select file",
InitialDirectory = InitDirectory
};
if (ofd.ShowDialog() == DialogResult.OK)
{
frameIndex = 0;
Inputs = MainGUI.ParseTasFile(ofd.FileName, out Resets);
string extension = Path.GetExtension(ofd.FileName);
timelineScrollbar.Maximum = Inputs.Count + 38;
MainGUI.Timeline_PendingHardReset = true;
if (extension != ".3c3")
{
LagFrames = new List();
TimelineSavestates = new List>();
TimelineTempSavestates = new List>();
// savestates are initialized in the Timeline_PendingArbitrarySavestate
MainGUI.Timeline_PendingArbitrarySavestate = true;
ScrollbarValue = 0;
timelineScrollbar.Value = 0;
TopFrame = 0;
highestFrameEmulatedEver = 0;
frameEmulated = 0;
}
if (extension == ".3c2")
{
byte[] b = File.ReadAllBytes(ofd.FileName); // Terribly inefficient to load the entire file a second time, but whatever.
ClockFiltering = (b[0] & 1) == 1;
}
if (extension == ".3c3")
{
byte[] b = File.ReadAllBytes(ofd.FileName); // Terribly inefficient to load the entire file a second time, but whatever.
ClockFiltering = (b[15] & 1) == 1;
}
RefreshTimeline();
GC.Collect();
}
}
private void saveTASToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
SaveFileDialog sfd = new SaveFileDialog()
{
FileName = "",
Filter = "TriCNES TAS File (.3c2)|*.3c2",
Title = "Save a .3c2 TAS File",
InitialDirectory = InitDirectory
};
sfd.ShowDialog();
if (sfd.FileName != "")
{
FileStream fs = (FileStream)sfd.OpenFile();
// Determine if controller 2 is used.
bool UseController2 = false;
for (int i = 0; i < Inputs.Count; i++)
{
if ((Inputs[i] & 0xFF00) != 0)
{
UseController2 = true;
break;
}
}
// Determine if the RESET button is used.
bool UseResets = false;
for (int i = 0; i < Inputs.Count; i++)
{
if (i < Resets.Count && Resets[i])
{
UseResets = true;
break;
}
}
byte Header = 0;
Header |= (byte)(ClockFiltering ? 1 : 0);
Header |= (byte)(UseController2 ? 2 : 0);
Header |= (byte)(UseResets ? 4 : 0);
fs.WriteByte(Header);
for (int i = 0; i < Inputs.Count; i++)
{
fs.WriteByte((byte)Inputs[i]);
if (UseController2) { fs.WriteByte((byte)(Inputs[i] >> 8)); }
if (UseResets) { fs.WriteByte((byte)(Resets[i] ? 0x80 : 0)); }
}
fs.Close();
}
}
private void saveWithSavestatesToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
SaveFileDialog sfd = new SaveFileDialog()
{
FileName = "",
Filter = "TriCNES TAS File (.3c3)|*.3c3",
Title = "Save a .3c3 TAS File",
InitialDirectory = InitDirectory
};
sfd.ShowDialog();
if (sfd.FileName != "")
{
FileStream fs = (FileStream)sfd.OpenFile();
// save the length of the savestates
fs.WriteByte((byte)SavestateLength);
fs.WriteByte((byte)(SavestateLength >> 8));
fs.WriteByte((byte)(SavestateLength >> 16));
fs.WriteByte((byte)(SavestateLength >> 24));
// save the number of rerecords. (I personally don't care about this statistic, but other people do, so I'll add it!)
fs.WriteByte((byte)Rerecords);
fs.WriteByte((byte)(Rerecords >> 8));
fs.WriteByte((byte)(Rerecords >> 16));
fs.WriteByte((byte)(Rerecords >> 24));
// save the length of the TAS
fs.WriteByte((byte)Inputs.Count);
fs.WriteByte((byte)(Inputs.Count >> 8));
fs.WriteByte((byte)(Inputs.Count >> 16));
fs.WriteByte((byte)(Inputs.Count >> 24));
fs.WriteByte(0); // 3 currently unused bytes.
fs.WriteByte(0);
fs.WriteByte(0);
// Determine if controller 2 is used.
bool UseController2 = false;
for (int i = 0; i < Inputs.Count; i++)
{
if ((Inputs[i] & 0xFF00) != 0)
{
UseController2 = true;
break;
}
}
// Determine if the RESET button is used.
bool UseResets = false;
for (int i = 0; i < Inputs.Count; i++)
{
if (i < Resets.Count && Resets[i])
{
UseResets = true;
break;
}
}
byte Header15 = 0;
Header15 |= (byte)(ClockFiltering ? 1 : 0);
Header15 |= (byte)(UseController2 ? 2 : 0);
Header15 |= (byte)(UseResets ? 4 : 0);
fs.WriteByte(Header15);
for (int i = 0; i < Inputs.Count; i++)
{
fs.WriteByte((byte)Inputs[i]);
if (UseController2) { fs.WriteByte((byte)(Inputs[i] >> 8)); }
if (UseResets) { fs.WriteByte((byte)((Resets[i] ? 0x80 : 0) | (i < LagFrames.Count ? (LagFrames[i] ? 1 : 0) : 0))); }
}
for (int i = 0; i < TimelineSavestates.Count; i++)
{
if (TimelineSavestates[i].Count != 0)
{
// save the frame index
fs.WriteByte((byte)i);
fs.WriteByte((byte)(i >> 8));
fs.WriteByte((byte)(i >> 16));
fs.WriteByte((byte)(i >> 24));
// save every byte of the savestate
for (int j = 0; j < SavestateLength; j++)
{
fs.WriteByte(TimelineSavestates[i][j]);
}
}
}
fs.Close();
}
}
private void exportTor08ToolStripMenuItem_Click(object sender, EventArgs e)
{
string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"tas\"))
{
InitDirectory += @"tas\";
}
SaveFileDialog sfd = new SaveFileDialog()
{
FileName = "",
Filter = "Replay Device (.r08)|*.r08",
Title = "Save a .r08 TAS File",
InitialDirectory = InitDirectory
};
sfd.ShowDialog();
if (sfd.FileName != "")
{
FileStream fs = (FileStream)sfd.OpenFile();
if (ClockFiltering)
{
// the .r08 file format is identical to my input list.
for (int i = 0; i < Inputs.Count; i++)
{
fs.WriteByte((byte)Inputs[i]);
fs.WriteByte((byte)(Inputs[i] >> 8));
}
}
else
{
if (LagFrames.Count < Inputs.Count)
{
MessageBox.Show("The .r08 exporter needs to know which frames are lag frames.\nOnly frames that have been emulated on the timeline will be exported.");
}
for (int i = 0; i < Inputs.Count; i++)
{
// the .r08 file format doesn't include lag frames.
if (i < LagFrames.Count && !LagFrames[i])
{
fs.WriteByte((byte)Inputs[i]);
fs.WriteByte((byte)(Inputs[i] >> 8));
}
}
}
fs.Close();
}
}
bool Paused = true;
private void b_play_Click(object sender, EventArgs e)
{
Paused = !Paused;
b_play.Text = Paused ? "Paused" : "Running";
MainGUI.Timeline_PendingResume = !Paused;
MainGUI.Timeline_PendingPause = Paused;
if (Paused)
{
GC.Collect();
}
}
private void deleteFrameToolStripMenuItem_Click(object sender, EventArgs e)
{
Inputs.RemoveAt(frameIndex);
int HighlightedFrame = frameIndex;
if (HighlightedFrame < frameEmulated)
{
MarkStale(HighlightedFrame);
}
timelineScrollbar.Maximum = Inputs.Count + 38;
RefreshTimeline();
}
private void insertFrameToolStripMenuItem_Click(object sender, EventArgs e)
{
Inputs.Insert(frameIndex, 0);
int HighlightedFrame = frameIndex;
if (HighlightedFrame < frameEmulated)
{
MarkStale(HighlightedFrame);
}
timelineScrollbar.Maximum = Inputs.Count + 38;
RefreshTimeline();
}
public bool Player2()
{
return cb_player2.Checked;
}
private void truncateMovieToolStripMenuItem_Click(object sender, EventArgs e)
{
Inputs.RemoveRange(frameIndex + 1, Inputs.Count - (frameIndex + 1));
if (TimelineSavestates.Count > frameIndex)
{
TimelineSavestates.RemoveRange(frameIndex + 1, TimelineSavestates.Count - (frameIndex + 1));
}
if (TimelineTempSavestates.Count > frameIndex)
{
TimelineTempSavestates.RemoveRange(frameIndex + 1, TimelineTempSavestates.Count - (frameIndex + 1));
}
if (LagFrames.Count > frameIndex)
{
LagFrames.RemoveRange(frameIndex, LagFrames.Count - (frameIndex));
}
System.GC.Collect();
highestFrameEmulatedEver = frameIndex;
frameEmulated = frameIndex;
timelineScrollbar.Maximum = Inputs.Count + 38;
RefreshTimeline();
}
private void b_JumptoCursor_Click(object sender, EventArgs e)
{
int scroll = frameIndex - FollowDistance;
if (scroll < 0)
{
scroll = 0;
}
timelineScrollbar.Value = scroll;
TopFrame = scroll;
RefreshTimeline();
}
public void RefreshTimeline()
{
// redraw the entire timeline's bitmap.
for (int i = 0; i < 40; i++)
{
int frame = TopFrame + i;
RecalculateTimelineRow(i, frame < Inputs.Count ? Inputs[frame] : (ushort)0);
TimelineGrid[i][17].Checked = false;
if (frame >= 0 && frame < Resets.Count)
{
TimelineGrid[i][17].Checked = Resets[frame];
}
RedrawTimelineRow(i, true);
}
MethodInvoker upd = delegate
{
pb_Timeline.Image = timelineBitmap;
pb_Timeline.Update();
};
this.Invoke(upd);
}
public void RedrawTimelineRow(int row, bool batch)
{
if (row < 0 || row >= TimelineGrid.Count)
{
return;
}
MethodInvoker upd = delegate
{
int rowp1 = row + 1;
Rectangle[] GridOverlay = new Rectangle[]
{
new Rectangle(0,rowp1*16,80,16),
new Rectangle(80 + 16*0,rowp1*16,16,16),
new Rectangle(80 + 16*1,rowp1*16,16,16),
new Rectangle(80 + 16*2,rowp1*16,16,16),
new Rectangle(80 + 16*3,rowp1*16,16,16),
new Rectangle(80 + 16*4,rowp1*16,16,16),
new Rectangle(80 + 16*5,rowp1*16,16,16),
new Rectangle(80 + 16*6,rowp1*16,16,16),
new Rectangle(80 + 16*7,rowp1*16,16,16),
new Rectangle(80 + 16*8,rowp1*16,16,16),
new Rectangle(80 + 16*9,rowp1*16,16,16),
new Rectangle(80 + 16*10,rowp1*16,16,16),
new Rectangle(80 + 16*11,rowp1*16,16,16),
new Rectangle(80 + 16*12,rowp1*16,16,16),
new Rectangle(80 + 16*13,rowp1*16,16,16),
new Rectangle(80 + 16*14,rowp1*16,16,16),
new Rectangle(80 + 16*15,rowp1*16,16,16),
new Rectangle(80 + 16*16,rowp1*16,16,16)
};
if (frameIndex - TopFrame == row)
{
G.FillRectangle(Brush_HighlightedCell, new Rectangle(0, rowp1 * 16, 80 + 16 * 17, 16));
}
else if (!TimelineGrid[row][0].Emulated)
{
G.FillRectangle(Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));
G.FillRectangle(Brush_WhiteCellP1, new Rectangle(80, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(Brush_WhiteCellP2, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(Brush_WhiteCellP1, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));
}
else if (TimelineGrid[row][0].Stale)
{
G.FillRectangle(Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1_Stale : Brush_GreenCellP1_Stale, new Rectangle(80, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP2_Stale : Brush_GreenCellP2_Stale, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1_Stale : Brush_GreenCellP1_Stale, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));
}
else
{
G.FillRectangle(TimelineSavestates[row + TopFrame].Count == SavestateLength ? Brush_LeftColumn_Saved : TimelineTempSavestates[row + TopFrame].Count == SavestateLength ? Brush_LeftColumn_TempSaved : Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1 : Brush_GreenCellP1, new Rectangle(80, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP2 : Brush_GreenCellP2, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));
G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1 : Brush_GreenCellP1, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));
}
G.DrawRectangles(Pens.Black, GridOverlay);
string rownum = (row + TopFrame).ToString();
//if(row + TopFrame < TEMPRerecordTracker.Count)
//{
// rownum += " (" + TEMPRerecordTracker[row + TopFrame].ToString() + ")";
//}
G.DrawString(rownum, Font_Consolas, Brushes.Black, 0, rowp1 * 16);
if (TimelineGrid[row][1].Checked) { G.DrawString("A", Font_Consolas, Brushes.Black, 80 + 16 * 0, rowp1 * 16); }
if (TimelineGrid[row][2].Checked) { G.DrawString("B", Font_Consolas, Brushes.Black, 80 + 16 * 1, rowp1 * 16); }
if (TimelineGrid[row][3].Checked) { G.DrawString("s", Font_Consolas, Brushes.Black, 80 + 16 * 2, rowp1 * 16); }
if (TimelineGrid[row][4].Checked) { G.DrawString("S", Font_Consolas, Brushes.Black, 80 + 16 * 3, rowp1 * 16); }
if (TimelineGrid[row][5].Checked) { G.DrawString("U", Font_Consolas, Brushes.Black, 80 + 16 * 4, rowp1 * 16); }
if (TimelineGrid[row][6].Checked) { G.DrawString("D", Font_Consolas, Brushes.Black, 80 + 16 * 5, rowp1 * 16); }
if (TimelineGrid[row][7].Checked) { G.DrawString("L", Font_Consolas, Brushes.Black, 80 + 16 * 6, rowp1 * 16); }
if (TimelineGrid[row][8].Checked) { G.DrawString("R", Font_Consolas, Brushes.Black, 80 + 16 * 7, rowp1 * 16); }
if (TimelineGrid[row][9].Checked) { G.DrawString("A", Font_Consolas, Brushes.Black, 80 + 16 * 8, rowp1 * 16); }
if (TimelineGrid[row][10].Checked) { G.DrawString("B", Font_Consolas, Brushes.Black, 80 + 16 * 9, rowp1 * 16); }
if (TimelineGrid[row][11].Checked) { G.DrawString("s", Font_Consolas, Brushes.Black, 80 + 16 * 10, rowp1 * 16); }
if (TimelineGrid[row][12].Checked) { G.DrawString("S", Font_Consolas, Brushes.Black, 80 + 16 * 11, rowp1 * 16); }
if (TimelineGrid[row][13].Checked) { G.DrawString("U", Font_Consolas, Brushes.Black, 80 + 16 * 12, rowp1 * 16); }
if (TimelineGrid[row][14].Checked) { G.DrawString("D", Font_Consolas, Brushes.Black, 80 + 16 * 13, rowp1 * 16); }
if (TimelineGrid[row][15].Checked) { G.DrawString("L", Font_Consolas, Brushes.Black, 80 + 16 * 14, rowp1 * 16); }
if (TimelineGrid[row][16].Checked) { G.DrawString("R", Font_Consolas, Brushes.Black, 80 + 16 * 15, rowp1 * 16); }
if (TimelineGrid[row][17].Checked) { G.DrawString("r", Font_Consolas, Brushes.Black, 80 + 16 * 16, rowp1 * 16); }
if (!batch)
{
pb_Timeline.Image = timelineBitmap;
pb_Timeline.Update();
}
};
this.BeginInvoke(upd);
}
public void RecalculateTimelineRow(int row, ushort input)
{
// redraw one row of the timeline
if (row < 0 || row >= TimelineGrid.Count)
{
return;
}
TimelineGrid[row][8].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][7].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][6].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][5].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][4].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][3].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][2].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][1].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][16].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][15].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][14].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][13].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][12].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][11].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][10].Checked = (input & 1) == 1;
input >>= 1;
TimelineGrid[row][9].Checked = (input & 1) == 1;
UpdateTimelineRowStatus(row);
}
public void UpdateTimelineRowStatus(int row)
{
if (row < 0 || row >= TimelineGrid.Count)
{
return;
}
// redraw one row of the timeline
int frame = (TopFrame + row);
bool Emulated = frame < highestFrameEmulatedEver;
bool Stale = Emulated && (frame > frameEmulated);
bool LagFrame = false;
if (LagFrames.Count > frame)
{
LagFrame = Emulated && (LagFrames[frame]);
}
TimelineGrid[row][0].Emulated = Emulated;
TimelineGrid[row][0].Stale = Stale;
TimelineGrid[row][0].LagFrame = LagFrame;
}
int FollowDistance = 20;
private void tb_FollowDistance_Scroll(object sender, EventArgs e)
{
FollowDistance = tb_FollowDistance.Value;
}
public bool SavestateEveryFrame()
{
return cb_SavestateEveryFrame.Checked;
}
public bool RecordInputs()
{
return cb_RecordInputs.Checked;
}
List GrabMostRecentSavestate()
{
int l = TimelineSavestates[frameIndex].Count;
if (l != SavestateLength)
{
l = TimelineTempSavestates[frameIndex].Count;
if (l == SavestateLength)
{
return TimelineTempSavestates[frameIndex];
}
}
bool temp = false;
while (l != SavestateLength)
{
frameIndex--;
l = TimelineSavestates[frameIndex].Count;
if (l != SavestateLength)
{
l = TimelineTempSavestates[frameIndex].Count;
if (l == SavestateLength)
{
temp = true;
break;
}
}
}
return temp ? TimelineTempSavestates[frameIndex] : TimelineSavestates[frameIndex];
}
List GrabMostRecentSavestate(int TargetFrame, out bool HitTargetFrame)
{
if (frameIndex == TargetFrame)
{
HitTargetFrame = true;
return null;
}
bool temp = false;
int l = TimelineSavestates[frameIndex].Count;
if (l != SavestateLength)
{
l = TimelineTempSavestates[frameIndex].Count;
if (l == SavestateLength)
{
HitTargetFrame = false;
return TimelineTempSavestates[frameIndex];
}
}
while (l != SavestateLength)
{
frameIndex--;
if (frameIndex == TargetFrame)
{
HitTargetFrame = true;
return null;
}
l = TimelineSavestates[frameIndex].Count;
if (l != SavestateLength)
{
l = TimelineTempSavestates[frameIndex].Count;
if (l == SavestateLength)
{
temp = true;
break;
}
}
}
HitTargetFrame = false;
return temp ? TimelineTempSavestates[frameIndex] : TimelineSavestates[frameIndex];
}
private void savestateThisFrameToolStripMenuItem_Click(object sender, EventArgs e)
{
if (frameIndex == TimelineSavestates.Count)
{
List state = MainGUI.EMU.SaveState();
TimelineSavestates.Add(state);
if (TimelineTempSavestates[frameIndex].Count > 0)
{
TimelineTempSavestates[frameIndex] = new List(); // remove temp savestate for this frame
}
}
else
{
List state = MainGUI.EMU.SaveState();
TimelineSavestates[frameIndex] = state;
if (TimelineTempSavestates[frameIndex].Count > 0)
{
TimelineTempSavestates[frameIndex] = new List(); // remove temp savestate for this frame
}
GC.Collect();
}
}
public void TrimTempSavestates()
{
int deletion = frameIndex - TempSavestates;
if (deletion >= 0 && deletion < TimelineTempSavestates.Count && TimelineTempSavestates[deletion].Count > 0)
{
TimelineTempSavestates[deletion] = new List(); // remove temp savestate for this frame
int row = deletion - TopFrame;
if (row >= 0 && row < 40)
{
UpdateTimelineRowStatus(row);
RedrawTimelineRow(row, false);
}
}
}
private void tb_FilterForNumbers(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
private void tb_AutoSavestateThreshold_TextChanged(object sender, EventArgs e)
{
int i = 0;
if (int.TryParse(tb_AutoSavestateThreshold.Text, out i))
{
AutoSavestateThreshold = i;
}
}
private void tb_TempSavestates_TextChanged(object sender, EventArgs e)
{
int i = 0;
if (int.TryParse(tb_TempSavestates.Text, out i))
{
TempSavestates = i;
}
}
public void ChangePlayPauseButtonText(string str)
{
MethodInvoker upd = delegate
{
b_play.Text = str;
b_play.Update();
};
this.Invoke(upd);
}
public bool ClockFiltering;
private void perVBlankToolStripMenuItem_Click(object sender, EventArgs e)
{
perVBlankToolStripMenuItem.Checked = true;
perControllerStrobeToolStripMenuItem.Checked = false;
ClockFiltering = false;
// reset the TAS and mark everything as stale!
ResetTASAndMarkEverythingStale();
MainGUI.Timeline_PendingClockFiltering = false;
RefreshTopOfTimeline();
}
private void perControllerStrobeToolStripMenuItem_Click(object sender, EventArgs e)
{
perVBlankToolStripMenuItem.Checked = false;
perControllerStrobeToolStripMenuItem.Checked = true;
ClockFiltering = true;
ResetTASAndMarkEverythingStale();
MainGUI.Timeline_PendingClockFiltering = true;
RefreshTopOfTimeline();
}
void ResetTASAndMarkEverythingStale()
{
frameIndex = 0;
timelineScrollbar.Maximum = Inputs.Count + 38;
MainGUI.Timeline_PendingHardReset = true;
LagFrames = new List();
TimelineSavestates = new List>();
TimelineTempSavestates = new List>();
// savestates are initialized in the Timeline_PendingArbitrarySavestate
MainGUI.Timeline_PendingArbitrarySavestate = true;
ScrollbarValue = 0;
timelineScrollbar.Value = 0;
TopFrame = 0;
highestFrameEmulatedEver = 0;
frameEmulated = 0;
RefreshTimeline();
}
}
}
================================================
FILE: forms/TriCTASTimeline.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
17, 17
True
132, 17
331, 17
In order to move backwards on the timeline, the emulator needs to keep savestetes for earlier frames.
Savestates require copies of every variable in the emulator, and can be a bit RAM consuming.
These temporary savestates will record the previous 'n' frames before being deleted, allowing you to fix mistakes in the previous 'n' frames.
You could also choose to create a savestate on every frame if you would prefer.
In order to move backwards on the timeline, the emulator needs to keep savestetes for earlier frames.
Savestates require copies of every variable in the emulator, and can be a bit RAM consuming.
These temporary savestates will record the previous 'n' frames before being deleted, allowing you to fix mistakes in the previous 'n' frames.
You could also choose to create a savestate on every frame if you would prefer.
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: forms/TriCTraceLogger.Designer.cs
================================================
namespace TriCNES
{
partial class TriCTraceLogger
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCTraceLogger));
this.b_ToggleButton = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.rtb_TraceLog = new System.Windows.Forms.RichTextBox();
this.cb_LogInRange = new System.Windows.Forms.CheckBox();
this.tb_RangeLow = new System.Windows.Forms.TextBox();
this.tb_RangeHigh = new System.Windows.Forms.TextBox();
this.cb_ClearEveryFrame = new System.Windows.Forms.CheckBox();
this.cb_LogPPU = new System.Windows.Forms.CheckBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// b_ToggleButton
//
this.b_ToggleButton.Appearance = System.Windows.Forms.Appearance.Button;
this.b_ToggleButton.AutoSize = true;
this.b_ToggleButton.Location = new System.Drawing.Point(12, 497);
this.b_ToggleButton.Name = "b_ToggleButton";
this.b_ToggleButton.Size = new System.Drawing.Size(80, 23);
this.b_ToggleButton.TabIndex = 0;
this.b_ToggleButton.Text = "Start Logging";
this.b_ToggleButton.UseVisualStyleBackColor = true;
this.b_ToggleButton.CheckedChanged += new System.EventHandler(this.b_ToggleButton_CheckedChanged);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.rtb_TraceLog);
this.groupBox1.Location = new System.Drawing.Point(12, 27);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(931, 464);
this.groupBox1.TabIndex = 1;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Trace Log";
//
// rtb_TraceLog
//
this.rtb_TraceLog.DetectUrls = false;
this.rtb_TraceLog.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.rtb_TraceLog.Location = new System.Drawing.Point(7, 20);
this.rtb_TraceLog.Name = "rtb_TraceLog";
this.rtb_TraceLog.Size = new System.Drawing.Size(918, 438);
this.rtb_TraceLog.TabIndex = 56;
this.rtb_TraceLog.Text = "";
this.rtb_TraceLog.WordWrap = false;
//
// cb_LogInRange
//
this.cb_LogInRange.AutoSize = true;
this.cb_LogInRange.Location = new System.Drawing.Point(165, 498);
this.cb_LogInRange.Name = "cb_LogInRange";
this.cb_LogInRange.Size = new System.Drawing.Size(139, 17);
this.cb_LogInRange.TabIndex = 2;
this.cb_LogInRange.Text = "Only Log Within Range:";
this.cb_LogInRange.UseVisualStyleBackColor = true;
this.cb_LogInRange.CheckedChanged += new System.EventHandler(this.cb_LogInRange_CheckedChanged);
//
// tb_RangeLow
//
this.tb_RangeLow.Enabled = false;
this.tb_RangeLow.Location = new System.Drawing.Point(298, 495);
this.tb_RangeLow.MaxLength = 4;
this.tb_RangeLow.Name = "tb_RangeLow";
this.tb_RangeLow.ReadOnly = true;
this.tb_RangeLow.Size = new System.Drawing.Size(32, 20);
this.tb_RangeLow.TabIndex = 3;
this.tb_RangeLow.Text = "0000";
this.tb_RangeLow.TextChanged += new System.EventHandler(this.tb_RangeLow_TextChanged);
//
// tb_RangeHigh
//
this.tb_RangeHigh.Enabled = false;
this.tb_RangeHigh.Location = new System.Drawing.Point(336, 495);
this.tb_RangeHigh.MaxLength = 4;
this.tb_RangeHigh.Name = "tb_RangeHigh";
this.tb_RangeHigh.ReadOnly = true;
this.tb_RangeHigh.Size = new System.Drawing.Size(32, 20);
this.tb_RangeHigh.TabIndex = 4;
this.tb_RangeHigh.Text = "FFFF";
this.tb_RangeHigh.TextChanged += new System.EventHandler(this.tb_RangeHigh_TextChanged);
//
// cb_ClearEveryFrame
//
this.cb_ClearEveryFrame.AutoSize = true;
this.cb_ClearEveryFrame.Checked = true;
this.cb_ClearEveryFrame.CheckState = System.Windows.Forms.CheckState.Checked;
this.cb_ClearEveryFrame.Location = new System.Drawing.Point(165, 521);
this.cb_ClearEveryFrame.Name = "cb_ClearEveryFrame";
this.cb_ClearEveryFrame.Size = new System.Drawing.Size(133, 17);
this.cb_ClearEveryFrame.TabIndex = 5;
this.cb_ClearEveryFrame.Text = "Clear Log Every Frame";
this.cb_ClearEveryFrame.UseVisualStyleBackColor = true;
//
// cb_LogPPU
//
this.cb_LogPPU.AutoSize = true;
this.cb_LogPPU.Location = new System.Drawing.Point(165, 548);
this.cb_LogPPU.Name = "cb_LogPPU";
this.cb_LogPPU.Size = new System.Drawing.Size(103, 17);
this.cb_LogPPU.TabIndex = 6;
this.cb_LogPPU.Text = "Log PPU Cycles";
this.cb_LogPPU.UseVisualStyleBackColor = true;
//
// TriCTraceLogger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(953, 577);
this.Controls.Add(this.cb_LogPPU);
this.Controls.Add(this.cb_ClearEveryFrame);
this.Controls.Add(this.tb_RangeHigh);
this.Controls.Add(this.tb_RangeLow);
this.Controls.Add(this.cb_LogInRange);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.b_ToggleButton);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(969, 616);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(969, 616);
this.Name = "TriCTraceLogger";
this.Text = "Trace Logger";
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox b_ToggleButton;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.RichTextBox rtb_TraceLog;
private System.Windows.Forms.CheckBox cb_LogInRange;
private System.Windows.Forms.TextBox tb_RangeLow;
private System.Windows.Forms.TextBox tb_RangeHigh;
private System.Windows.Forms.CheckBox cb_ClearEveryFrame;
private System.Windows.Forms.CheckBox cb_LogPPU;
}
}
================================================
FILE: forms/TriCTraceLogger.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TriCNES
{
public partial class TriCTraceLogger : Form
{
public TriCNESGUI MainGUI;
public bool Logging;
public TriCTraceLogger()
{
InitializeComponent();
FormClosing += new FormClosingEventHandler(TriCTraceLogger_Closing);
}
private void TriCTraceLogger_Closing(Object sender, FormClosingEventArgs e)
{
MainGUI.TraceLogger = null;
}
public void Init()
{
rtb_TraceLog.SelectionTabs = new int[] { 0, 56, 56 * 2, 56 * 3, 56 * 4, 56 * 5, 56 * 6, 56 * 7, 56 * 8, 56 * 9, 56 * 10 };
}
String Log;
public void Update()
{
if (MainGUI.EMU.DebugLog != null)
{
Log = MainGUI.EMU.DebugLog.ToString();
MethodInvoker upd = delegate
{
rtb_TraceLog.Text = Log;
};
try
{
this.Invoke(upd);
}
catch (Exception e)
{
}
}
}
private void b_ToggleButton_CheckedChanged(object sender, EventArgs e)
{
Logging = b_ToggleButton.Checked;
b_ToggleButton.Text = Logging ? "Stop Logging" : "Start Logging";
}
private void cb_LogInRange_CheckedChanged(object sender, EventArgs e)
{
tb_RangeHigh.ReadOnly = !cb_LogInRange.Checked;
tb_RangeHigh.Enabled = cb_LogInRange.Checked;
tb_RangeLow.ReadOnly = !cb_LogInRange.Checked;
tb_RangeLow.Enabled = cb_LogInRange.Checked;
}
private void tb_RangeLow_TextChanged(object sender, EventArgs e)
{
RangeLow = 0;
ushort.TryParse(tb_RangeLow.Text, System.Globalization.NumberStyles.HexNumber, null, out RangeLow);
}
private void tb_RangeHigh_TextChanged(object sender, EventArgs e)
{
RangeHigh = 0xFFFF;
ushort.TryParse(tb_RangeHigh.Text, System.Globalization.NumberStyles.HexNumber, null, out RangeHigh);
}
public ushort RangeLow;
public ushort RangeHigh;
public bool OnlyDebugInRange()
{
return cb_LogInRange.Checked;
}
public bool ClearEveryFrame()
{
return cb_ClearEveryFrame.Checked;
}
public bool LogPPUCycles()
{
return cb_LogPPU.Checked;
}
}
}
================================================
FILE: forms/TriCTraceLogger.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA
AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA
AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////
//////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA
AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//
/////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA
AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//
////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA
AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////
//8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA
AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA
AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA
AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//
////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA
AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA
AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////
//8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA
AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA
AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////
////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////
//8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA
AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////
/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA
zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////
//////////////////////////////////8=
================================================
FILE: mappers/Mapper_AOROM.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
namespace TriCNES.mappers
{
public class Mapper_AOROM : Mapper
{
// ines Mapper 7
public byte Mapper_7_BankSelect;
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0x8000)
{
dataPinsAreNotFloating = true;
ushort tempo = (ushort)(Address & 0x7FFF);
dataBus = Cart.PRGROM[(0x8000 * (Mapper_7_BankSelect & 0x07) + tempo) & (Cart.PRGROM.Length - 1)];
}
// AOROM doesn't have any PRG RAM
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address >= 0x8000)
{
Mapper_7_BankSelect = Input;
}
}
public override ushort MirrorNametable(ushort Address)
{
if ((Mapper_7_BankSelect & 0x10) == 0) // show nametable 0
{
Address &= 0x33FF;
}
else // show nametable 1
{
Address &= 0x33FF;
Address |= 0x400;
}
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_7_BankSelect);
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_7_BankSelect = State[p++];
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_CNROM.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_CNROM : Mapper
{
// ines Mapper 3
public byte Mapper_3_CHRBank;
public override void StorePRG(ushort Address, byte Input)
{
if (Address >= 0x8000)
{
Mapper_3_CHRBank = (byte)(Input & 0x3);
}
}
public override byte FetchCHR(ushort Address, bool Observe)
{
return Cart.CHRROM[(Mapper_3_CHRBank * 0x2000 + Address) & (Cart.CHRROM.Length - 1)];
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_3_CHRBank);
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_3_CHRBank = State[p++];
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_FDS.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_FDS : Mapper
{
// The Famicom Disk System
public byte[] FDS_BIOS;
public byte FDS_4023_IOEnable;
public byte FDS_4025_Control;
public Mapper_FDS(byte[] fds_bios)
{
FDS_BIOS = fds_bios;
}
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0xE000)
{
// read from the FDS BIOS
notFloating = true;
data = FDS_BIOS[Address & 0x1FFF];
}
else if (Address >= 0x6000)
{
// read from the FDS PRG RAM
notFloating = true;
data = Cart.PRGRAM[Address-0x6000];
}
else if (Address >= 4030 && Address <= 0x403F)
{
// Read from the FDS Registers
Address &= 0xF;
switch (Address)
{
default: break;
case 0:
{
// FDS Status ($4030)
notFloating = true;
data = 0;
data |= (byte)((FDS_4025_Control >> 3) & 1); // 4030.3 = 4025.3
data |= (byte)(Cart.FDS.Status_ByteTransferFlag ? 0x80 : 0); // 4030.7 = Byte Transfer Flag
}
break;
case 1:
{
// Disk Data Input ($4031)
notFloating = true;
data = Cart.FDS.ShiftRegisterLatch;
Cart.FDS.Status_ByteTransferFlag = false;
Cart.Emu.IRQ_LevelDetector = false; //acknowledge the IRQ
}
break;
case 2:
{
// Disk Drive Status ($4032)
}
break;
case 3:
{
// External Connector Input ($4033)
notFloating = true;
data = 0x80; // The battery is good.
}
break;
}
}
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override byte FetchCHR(ushort Address, bool Observe)
{
return Cart.CHRRAM[Address];
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address >= 0x6000 && Address < 0xE000)
{
Cart.PRGRAM[Address-0x6000] = Input;
return;
}
else if (Address > 0x401F)
{
ushort tempo = (ushort)(Address & 0x40FF);
switch (tempo)
{
case 0x4023:
FDS_4023_IOEnable = Input;
if((FDS_4023_IOEnable & 1) == 0)
{
// Disable disk I/O registers
Cart.Emu.IRQ_LevelDetector = false; //acknowledge the IRQ
FDS_4025_Control = 6;
}
return;
case 0x4024:
Cart.FDS.Status_ByteTransferFlag = false;
return;
case 0x4025:
FDS_4025_Control = Input;
return;
}
}
}
public override void FDS_ByteTransferFlag()
{
if((FDS_4025_Control & 0x80) != 0)
{
Cart.Emu.IRQ_LevelDetector = true;
}
}
public override byte FDS_Get4025()
{
return FDS_4025_Control;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(FDS_4025_Control);
State.Add((byte)Cart.FDS.clock);
State.Add((byte)(Cart.FDS.clock >> 8));
State.Add((byte)Cart.FDS.ShiftRegister);
State.Add((byte)Cart.FDS.ShiftRegisterLatch);
State.Add((byte)Cart.FDS.DiskAddress);
State.Add((byte)(Cart.FDS.DiskAddress >> 8));
State.Add((byte)Cart.FDS.DiskAddressFine);
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
FDS_4025_Control = State[p++];
Cart.FDS.clock = State[p++];
Cart.FDS.clock |= (ushort)(State[p++] << 8);
Cart.FDS.ShiftRegister = State[p++];
Cart.FDS.ShiftRegisterLatch = State[p++];
Cart.FDS.DiskAddress = State[p++];
Cart.FDS.DiskAddress |= (ushort)(State[p++] << 8);
Cart.FDS.DiskAddressFine = State[p++];
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_FME7.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_FME7 : Mapper
{
// ines Mapper 69
public byte Mapper_69_CMD;
public byte Mapper_69_CHR_1K0;
public byte Mapper_69_CHR_1K1;
public byte Mapper_69_CHR_1K2;
public byte Mapper_69_CHR_1K3;
public byte Mapper_69_CHR_1K4;
public byte Mapper_69_CHR_1K5;
public byte Mapper_69_CHR_1K6;
public byte Mapper_69_CHR_1K7;
public byte Mapper_69_Bank_6;
public bool Mapper_69_Bank_6_isRAM;
public bool Mapper_69_Bank_6_isRAMEnabled;
public byte Mapper_69_Bank_8;
public byte Mapper_69_Bank_A;
public byte Mapper_69_Bank_C;
public byte Mapper_69_NametableMirroring; // 0 = Vertical 1 = Horizontal 2 = One Screen Mirroring from $2000 ("1ScA") 3 = One Screen Mirroring from $2400 ("1ScB")
public bool Mapper_69_EnableIRQ;
public bool Mapper_69_EnableIRQCounterDecrement;
public ushort Mapper_69_IRQCounter; // When enabled the 16-bit IRQ counter is decremented once per CPU cycle. When the IRQ counter is decremented from $0000 to $FFFF an IRQ is generated.
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0x6000)
{
ushort tempo = (ushort)(Address % 0x2000);
if (Address >= 0x6000)
{
//actions
if (Address < 0x8000)
{
if (Mapper_69_Bank_6_isRAM)
{
if (Mapper_69_Bank_6_isRAMEnabled)
{
notFloating = true;
data = Cart.PRGRAM[Address & 0x1FFF];
}
}
else
{ //read from ROM
notFloating = true;
data = Cart.PRGROM[(Mapper_69_Bank_6 * 0x2000 + tempo) % Cart.PRGROM.Length];
}
}
else if (Address < 0xA000)
{
notFloating = true;
data = Cart.PRGROM[(Mapper_69_Bank_8 * 0x2000 + tempo) % Cart.PRGROM.Length];
}
else if (Address < 0xC000)
{
notFloating = true;
data = Cart.PRGROM[(Mapper_69_Bank_A * 0x2000 + tempo) % Cart.PRGROM.Length];
}
else if (Address < 0xE000)
{
notFloating = true;
data = Cart.PRGROM[(Mapper_69_Bank_C * 0x2000 + tempo) % Cart.PRGROM.Length];
}
else
{
notFloating = true;
data = Cart.PRGROM[Cart.PRGROM.Length - 0x2000 + tempo];
}
}
}
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address >= 0x6000)
{
//actions
if (Address < 0x8000)
{
if (Mapper_69_Bank_6_isRAM)
{
if (Mapper_69_Bank_6_isRAMEnabled)
{
//writing to RAM
Cart.PRGRAM[Address & 0x1FFF] = Input;
} //else, writing to open bus
} //else it's ROM. writing here does nothing.
}
else if (Address < 0xA000)
{
Mapper_69_CMD = (byte)(Input & 0x0F);
}
else if (Address < 0xC000)
{
switch (Mapper_69_CMD)
{
case 0: Mapper_69_CHR_1K0 = Input; break;
case 1: Mapper_69_CHR_1K1 = Input; break;
case 2: Mapper_69_CHR_1K2 = Input; break;
case 3: Mapper_69_CHR_1K3 = Input; break;
case 4: Mapper_69_CHR_1K4 = Input; break;
case 5: Mapper_69_CHR_1K5 = Input; break;
case 6: Mapper_69_CHR_1K6 = Input; break;
case 7: Mapper_69_CHR_1K7 = Input; break;
case 8: Mapper_69_Bank_6 = (byte)(Input & 0x3F); Mapper_69_Bank_6_isRAM = (Input & 0x40) != 0; Mapper_69_Bank_6_isRAMEnabled = (Input & 0x80) != 0; break;
case 9: Mapper_69_Bank_8 = (byte)(Input & 0x3F); break;
case 10: Mapper_69_Bank_A = (byte)(Input & 0x3F); break;
case 11: Mapper_69_Bank_C = (byte)(Input & 0x3F); break;
case 12: Mapper_69_NametableMirroring = (byte)(Input & 0x3); break;
case 13: Mapper_69_EnableIRQ = (Input & 0x1) != 0; Mapper_69_EnableIRQCounterDecrement = (Input & 0x80) != 0; Cart.Emu.IRQ_LevelDetector = false; break;
case 14: Mapper_69_IRQCounter = (ushort)((Mapper_69_IRQCounter & 0xFF00) | Input); break;
case 15: Mapper_69_IRQCounter = (ushort)((Mapper_69_IRQCounter & 0xFF) | (Input << 8)); break;
}
} // else do nothing
}
}
public override byte FetchCHR(ushort Address, bool Observe)
{
if (Address < 0x400) { return Cart.CHRROM[(Mapper_69_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K1 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0xC00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K2 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1000) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K3 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1400) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K5 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1C00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K6 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K7 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
}
public override ushort MirrorNametable(ushort Address)
{
switch (Mapper_69_NametableMirroring)
{
case 0: //vertical
Address &= 0x37FF; // mask away $0800
break;
case 1: //horizontal
Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11
break;
case 2: //one-screen A
Address &= 0x33FF;
break;
case 3: //one-screen B
Address &= 0x33FF;
Address |= 0x400;
break;
}
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_69_CMD);
State.Add(Mapper_69_CHR_1K0);
State.Add(Mapper_69_CHR_1K1);
State.Add(Mapper_69_CHR_1K2);
State.Add(Mapper_69_CHR_1K3);
State.Add(Mapper_69_CHR_1K4);
State.Add(Mapper_69_CHR_1K5);
State.Add(Mapper_69_CHR_1K6);
State.Add(Mapper_69_CHR_1K7);
State.Add(Mapper_69_Bank_6);
State.Add((byte)(Mapper_69_Bank_6_isRAM ? 1 : 0));
State.Add((byte)(Mapper_69_Bank_6_isRAMEnabled ? 1 : 0));
State.Add(Mapper_69_Bank_8);
State.Add(Mapper_69_Bank_A);
State.Add(Mapper_69_Bank_C);
State.Add(Mapper_69_NametableMirroring);
State.Add((byte)(Mapper_69_EnableIRQ ? 1 : 0));
State.Add((byte)(Mapper_69_EnableIRQCounterDecrement ? 1 : 0));
State.Add((byte)Mapper_69_IRQCounter);
State.Add((byte)(Mapper_69_IRQCounter >> 8));
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_69_CMD = State[p++];
Mapper_69_CHR_1K0 = State[p++];
Mapper_69_CHR_1K1 = State[p++];
Mapper_69_CHR_1K2 = State[p++];
Mapper_69_CHR_1K3 = State[p++];
Mapper_69_CHR_1K4 = State[p++];
Mapper_69_CHR_1K5 = State[p++];
Mapper_69_CHR_1K6 = State[p++];
Mapper_69_CHR_1K7 = State[p++];
Mapper_69_Bank_6 = State[p++];
Mapper_69_Bank_6_isRAM = (State[p++] & 1) == 1;
Mapper_69_Bank_6_isRAMEnabled = (State[p++] & 1) == 1;
Mapper_69_Bank_8 = State[p++];
Mapper_69_Bank_A = State[p++];
Mapper_69_Bank_C = State[p++];
Mapper_69_NametableMirroring = State[p++];
Mapper_69_EnableIRQ = (State[p++] & 1) == 1;
Mapper_69_EnableIRQCounterDecrement = (State[p++] & 1) == 1;
Mapper_69_IRQCounter = State[p++];
Mapper_69_IRQCounter |= (ushort)(State[p++] << 8);
exitIndex = p;
}
public override void CPUClock()
{
// The sunsoft FME-7 mapper chip has an IRQ counter that ticks down once per CPU cycle.
if (Mapper_69_EnableIRQCounterDecrement)
{
ushort temp = Mapper_69_IRQCounter;
Mapper_69_IRQCounter--;
if (Mapper_69_EnableIRQ && temp < Mapper_69_IRQCounter)
{
Cart.Emu.IRQ_LevelDetector = true;
}
}
}
}
}
================================================
FILE: mappers/Mapper_MMC1.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_MMC1 : Mapper
{
// ines Mapper 1
public byte Mapper_1_ShiftRegister;
public byte Mapper_1_Control = 0x0C; //0x8000
public byte Mapper_1_CHR0; //0xA000
public byte Mapper_1_CHR1; //0xC000
public byte Mapper_1_PRG; //0xE000
public bool Mapper_1_PB;
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0x8000)
{
notFloating = true;
// The bank mode for MMC1:
byte MMC1PRGROMBankMode = (byte)((Mapper_1_Control & 0b01100) >> 2);
switch (MMC1PRGROMBankMode)
{
case 0:
case 1:
{
// switch 32 KB at $8000, ignoring low bit of bank number
ushort tempo = (ushort)(Address & 0x7FFF);
data = Cart.PRGROM[(0x8000 * (Mapper_1_PRG & 0x0E) + tempo) % Cart.PRGROM.Length];
}
break;
case 2:
// fix first bank at $8000 and switch 16 KB bank at $C000
if (Address >= 0xC000)
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[0x4000 * (Mapper_1_PRG) + tempo];
}
else
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[tempo];
}
break;
case 3:
// fix last bank at $C000 and switch 16 KB bank at $8000
if (Address >= 0xC000)
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[Cart.PRGROM.Length - 0x4000 + tempo];
}
else
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[(0x4000 * (Mapper_1_PRG & 0x0F) + tempo) & (Cart.PRGROM.Length - 1)];
}
break;
}
}
else // if the address is < $8000
{
if (((Mapper_1_PRG & 0x10) == 0) && Address >= 0x6000) // if Work RAM is enabled
{
data = Cart.PRGRAM[Address & 0x1FFF];
notFloating = true;
}
// else, open bus.
}
//open bus
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address < 0x8000) //WRAM not available on MMC1A
{
if (((Mapper_1_PRG & 0x10) == 0) /*&& Mapper != 1*/)
{
//Battery backed RAM
Cart.PRGRAM[Address & 0x1FFF] = Input;
return;
}
else
{
return; //do nothing
}
}
else
{ // shift the shirftRegister and add the new bit
Mapper_1_PB = (Mapper_1_ShiftRegister & 1) == 1;
Mapper_1_ShiftRegister >>= 1;
Mapper_1_ShiftRegister |= (byte)((Input & 1) << 4);
}
if (Mapper_1_PB) // if the '1' that was initialized in bit 4 is shifted into the bus
{
// copy shift register to the desired internal register.
switch (Address & 0xE000)
{
case 0x8000: //control
Mapper_1_Control = Mapper_1_ShiftRegister;
break;
case 0xA000: //CHR0
Mapper_1_CHR0 = Mapper_1_ShiftRegister;
break;
case 0xC000: //CHR1
Mapper_1_CHR1 = Mapper_1_ShiftRegister;
break;
case 0xE000: //PRG
Mapper_1_PRG = Mapper_1_ShiftRegister;
break;
}
Mapper_1_ShiftRegister = 0b10000;
}
if ((Input & 0b10000000) != 0)
{
Mapper_1_ShiftRegister = 0b10000;
Mapper_1_Control |= 0b01100;
}
}
public override byte FetchCHR(ushort Address, bool Observe)
{
// bit 4 of Mapper_1_Control controls how the pattern tables are swapped. if set, 2 banks of 4Kib. Otherwise, 1 8Kib bank
if ((Mapper_1_Control & 0x10) != 0)
{
// with the MMC1 chip, you can swap out the pattern tables.
// address < 0x1000 is the first pattern table, else, the second pattern table.
// if the final write for the MMC1 shift register was in the $A000 - $BFFF, this updates Mapper_1_CHR0
// if the final write for the MMC1 shift register was in the $B000 - $CFFF, this updates Mapper_1_CHR1
if (Address < 0x1000) { return Cart.CHRROM[((Mapper_1_CHR0 & 0x1F) * 0x1000 + Address) & (Cart.CHRROM.Length - 1)]; }
else { Address &= 0xFFF; return Cart.CHRROM[((Mapper_1_CHR1 & 0x1F) * 0x1000 + Address) & (Cart.CHRROM.Length - 1)]; }
}
else // one swappable bank that changes both pattern tables.
{
// this uses the value written to Mapper_1_CHR0
return Cart.CHRROM[((Mapper_1_CHR0 & 0b11111110) * 0x2000 + Address) & (Cart.CHRROM.Length - 1)];
}
}
public override ushort MirrorNametable(ushort Address)
{
switch (Mapper_1_Control & 3)
{
case 0: //one screen, low
Address &= 0x33FF;
break;
case 1: //one screen, high
Address &= 0x33FF;
Address |= 0x400;
break;
case 2: //vertical
Address &= 0x37FF; // mask away $0800
break;
case 3: //horizontal
Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11
break;
}
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_1_ShiftRegister);
State.Add(Mapper_1_Control);
State.Add(Mapper_1_CHR0);
State.Add(Mapper_1_CHR1);
State.Add(Mapper_1_ShiftRegister);
State.Add((byte)(Mapper_1_PB ? 1 : 0));
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_1_ShiftRegister = State[p++];
Mapper_1_Control = State[p++];
Mapper_1_CHR0 = State[p++];
Mapper_1_CHR1 = State[p++];
Mapper_1_ShiftRegister = State[p++];
Mapper_1_PB = (State[p++] & 1) == 1;
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_MMC2.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_MMC2 : Mapper
{
// ines Mapper 9
public byte Mapper_9_BankSelect;
public byte Mapper_9_CHR0_FD;
public byte Mapper_9_CHR0_FE;
public byte Mapper_9_CHR1_FD;
public byte Mapper_9_CHR1_FE;
public bool Mapper_9_NametableMirroring;
public bool Mapper_9_Latch0_FE;
public bool Mapper_9_Latch1_FE;
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0xA000)
{
notFloating = true;
data = Cart.PRGROM[((Cart.PRG_Size - 2) << 14) | (Address & 0x7FFF)];
}
else if(Address >= 0x8000)
{
notFloating = true;
data = Cart.PRGROM[(Mapper_9_BankSelect << 13) | (Address & 0x1FFF)];
}
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address < 0xA000)
{
// nothing
}
else if (Address < 0xB000) // PRG Bank select
{
Mapper_9_BankSelect = (byte)(Input & 0x0F);
}
else if (Address < 0xC000) // CHR0 Bank select
{
Mapper_9_CHR0_FD = (byte)(Input & 0x1F);
}
else if (Address < 0xD000) // CHR0 Bank select
{
Mapper_9_CHR0_FE = (byte)(Input & 0x1F);
}
else if (Address < 0xE000) // CHR1 Bank select
{
Mapper_9_CHR1_FD = (byte)(Input & 0x1F);
}
else if (Address < 0xF000) // CHR1 Bank select
{
Mapper_9_CHR1_FE = (byte)(Input & 0x1F);
}
else // Nametable mirroring
{
Mapper_9_NametableMirroring = (Input & 0x1) == 1;
}
}
public override byte FetchCHR(ushort Address, bool Observe)
{
byte temp = 0;
ushort Addr = Address;
if (Address < 0x1000) { temp = Cart.CHRROM[(Mapper_9_Latch0_FE ? Mapper_9_CHR0_FE : Mapper_9_CHR0_FD) * 0x1000 + Addr]; }
else { Addr &= 0xFFF; temp = Cart.CHRROM[(Mapper_9_Latch1_FE ? Mapper_9_CHR1_FE : Mapper_9_CHR1_FD) * 0x1000 + Addr]; }
if (!Observe)
{
if (Address == 0x0FD8)
{
Mapper_9_Latch0_FE = false;
}
else if (Address == 0x0FE8)
{
Mapper_9_Latch0_FE = true;
}
else if (Address >= 0x1FD8 && Address <= 0x1FDF)
{
Mapper_9_Latch1_FE = false;
}
else if (Address >= 0x1FE8 && Address <= 0x1FEF)
{
Mapper_9_Latch1_FE = true;
}
}
return temp;
}
public override ushort MirrorNametable(ushort Address)
{
if (Mapper_9_NametableMirroring) //horizontal
{
Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11
}
else //vertical
{
Address &= 0x37FF; // mask away $0800
}
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_9_BankSelect);
State.Add(Mapper_9_CHR0_FD);
State.Add(Mapper_9_CHR0_FE);
State.Add(Mapper_9_CHR1_FD);
State.Add(Mapper_9_CHR1_FE);
State.Add((byte)(Mapper_9_NametableMirroring ? 1 : 0));
State.Add((byte)(Mapper_9_Latch0_FE ? 1 : 0));
State.Add((byte)(Mapper_9_Latch1_FE ? 1 : 0)); return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_9_BankSelect = State[p++];
Mapper_9_CHR0_FD = State[p++];
Mapper_9_CHR0_FE = State[p++];
Mapper_9_CHR1_FD = State[p++];
Mapper_9_CHR1_FE = State[p++];
Mapper_9_NametableMirroring = (State[p++] & 1) == 1;
Mapper_9_Latch0_FE = (State[p++] & 1) == 1;
Mapper_9_Latch1_FE = (State[p++] & 1) == 1;
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_MMC3.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_MMC3 : Mapper
{
// ines Mapper 4
public byte Mapper_4_8000; // The value written to $8000 (or any even address between $8000 and $9FFE)
public byte Mapper_4_BankA; // The PRG bank between $A000 and $BFFF
public byte Mapper_4_Bank8C; // The PRG bank that could either be at $8000 through 9FFF, or $C000 through $DFFF
public byte Mapper_4_CHR_2K0;
public byte Mapper_4_CHR_2K8;
public byte Mapper_4_CHR_1K0;
public byte Mapper_4_CHR_1K4;
public byte Mapper_4_CHR_1K8;
public byte Mapper_4_CHR_1KC;
public byte Mapper_4_IRQLatch;
public byte Mapper_4_IRQCounter;
public bool Mapper_4_EnableIRQ;
public bool Mapper_4_ReloadIRQCounter;
public bool Mapper_4_NametableMirroring; // MMC3 has it's own way of controlling how the nametables are mirrored.
public byte Mapper_4_PRGRAMProtect;
public byte Mapper_4_M2Filter;
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0xE000) // This bank is fixed the the final PRG bank of the ROM
{
notFloating = true;
data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x3FFF)];
}
else if (Address >= 0xC000)
{
notFloating = true;
if ((Mapper_4_8000 & 0x40) == 0x40)
{
//$C000 swappable
data = Cart.PRGROM[(Mapper_4_Bank8C << 13) | (Address & 0x1FFF)];
}
else
{
//$8000 swappable
data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x1FFF)];
}
}
else if (Address >= 0xA000)
{
notFloating = true;
//$8000 swappable
data = Cart.PRGROM[(Mapper_4_BankA << 13) | (Address & 0x1FFF)];
}
else if (Address >= 0x8000)
{
notFloating = true;
if ((Mapper_4_8000 & 0x40) == 0x40)
{
//$8000 swappable
data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x1FFF)];
}
else
{
//$C000 swappable
data = Cart.PRGROM[(Mapper_4_Bank8C << 13) | (Address & 0x1FFF)];
}
}
else if (Address >= 0x6000)
{
if (Cart.SubMapper == 1) // MMC6
{
if ((Mapper_4_8000 & 0x20) != 0)
{
// MMC6 differs from MMC3 since there's only 1Kib of PRG RAM
if (Address >= 0x7000 && Address <= 0x71FF)
{
if ((Mapper_4_PRGRAMProtect & 0x20) != 0)
{
notFloating = true;
data = Cart.PRGRAM[Address & 0x3FF];
}
}
else if (Address >= 0x7200 && Address <= 0x73FF)
{
if ((Mapper_4_PRGRAMProtect & 0x80) != 0)
{
notFloating = true;
data = Cart.PRGRAM[Address & 0x3FF];
}
}
}
}
else
{
if ((Mapper_4_PRGRAMProtect & 0x80) != 0)
{
notFloating = true;
data = Cart.PRGRAM[Address & 0x1FFF];
}
}
}
//else, open bus
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address < 0x8000)
{ //Battery backed RAM
if (Cart.SubMapper == 1) // MMC6
{
// MMC6 differs from MMC3 since there's only 1Kib of PRG RAM
if ((Mapper_4_8000 & 0x20) != 0)
{
if (Address >= 0x7000 && Address <= 0x71FF)
{
if ((Mapper_4_PRGRAMProtect & 0x10) != 0)
{
Cart.PRGRAM[Address & 0x3FF] = Input;
}
}
else if (Address >= 0x7200 && Address <= 0x73FF)
{
if ((Mapper_4_PRGRAMProtect & 0x40) != 0)
{
Cart.PRGRAM[Address & 0x3FF] = Input;
}
}
}
}
else if ((Mapper_4_PRGRAMProtect & 0xC0) != 0) // bit 7 enables PRG RAM, bit 6 enables writing there.
{
Cart.PRGRAM[Address & 0x1FFF] = Input;
}
return;
}
else
{
ushort tempo = (ushort)(Address & 0xE001);
switch (tempo)
{
case 0x8000:
Mapper_4_8000 = Input;
return;
case 0x8001:
byte mode = (byte)(Mapper_4_8000 & 7);
switch (mode)
{
case 0: //PPU ($0000 - $07FF) ?+ $1000
Mapper_4_CHR_2K0 = (byte)(Input & 0xFE);
return;
case 1: //PPU ($0800 - $0FFF) ?+ $1000
Mapper_4_CHR_2K8 = (byte)(Input & 0xFE);
return;
case 2: //PPU ($1000 - $13FF) ?- $1000
Mapper_4_CHR_1K0 = Input;
return;
case 3: //PPU ($1400 - $17FF) ?- $1000
Mapper_4_CHR_1K4 = Input;
return;
case 4: //PPU ($1800 - $1BFF) ?- $1000
Mapper_4_CHR_1K8 = Input;
return;
case 5: //PPU ($1C00 - $1FFF) ?- $1000
Mapper_4_CHR_1KC = Input;
return;
case 6: //PRG ($8000 - $9FFF) ?+ 0x4000
Mapper_4_Bank8C = (byte)(Input & (Cart.PRG_Size * 2 - 1));
return;
case 7: //PRG ($A000 - $BFFF)
Mapper_4_BankA = (byte)(Input & (Cart.PRG_Size * 2 - 1));
return;
}
return;
case 0xA000:
Mapper_4_NametableMirroring = (Input & 1) == 1;
return;
case 0xA001:
Mapper_4_PRGRAMProtect = Input;
return;
case 0xC000:
Mapper_4_IRQLatch = Input;
return;
case 0xC001:
Mapper_4_IRQCounter = 0xFF;
Mapper_4_ReloadIRQCounter = true;
return;
case 0xE000:
Mapper_4_EnableIRQ = false;
Cart.Emu.IRQ_LevelDetector = false;
return;
case 0xE001:
Mapper_4_EnableIRQ = true;
return;
}
}
}
public override byte FetchCHR(ushort Address, bool Observe)
{
//Writes to $8000 determine the mode, writes to $8001 determine the banks
if ((Mapper_4_8000 & 0x80) == 0) // bit 7 of the previous write to $8000 determines which pattern table is 2 2kb banks, and which is 4 1kb banks.
{
if (Address < 0x800) { return Cart.CHRROM[(Mapper_4_CHR_2K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1000) { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1400) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1C00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1KC * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
}
else
{
if (Address < 0x400) { return Cart.CHRROM[(Mapper_4_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0xC00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1000) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1KC * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else if (Address < 0x1800) { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
else { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }
}
}
public override byte FetchPPU()
{
// This will always use the upper 8 bits of the address bus | the octal latch. This replaces the lower 8 bits of the address bus.
ushort Address = (ushort)((Cart.Emu.PPU_AddressBus & 0x3F00) | Cart.Emu.PPU_OctalLatch);
bool CIRAM = Address >= 0x2000;
if (!CIRAM)
{
if (Cart.UsingCHRRAM)
{
Cart.Emu.PPU_AddressBus &= 0xFF00;
Cart.Emu.PPU_AddressBus |= Cart.CHRRAM[Address];
}
else
{
//Pattern Table
Cart.Emu.PPU_AddressBus &= 0xFF00;
Cart.Emu.PPU_AddressBus |= Cart.MapperChip.FetchCHR(Address, false);
}
}
else // if the VRAM address is >= $2000, we need to consider nametable mirroring.
{
Address = MirrorNametable(Address);
if (Cart.AlternativeNametableArrangement)
{
if ((Address & 0x800) != 0)
{
// using the extra PRG VRAM.
Address &= 0x7FF;
Cart.Emu.PPU_AddressBus &= 0xFF00;
Cart.Emu.PPU_AddressBus |= Cart.PRGVRAM[Address];
}
else
{
Address &= 0x7FF;
Cart.Emu.PPU_AddressBus &= 0xFF00;
Cart.Emu.PPU_AddressBus |= Cart.Emu.VRAM[Address];
}
}
else
{
Address &= 0x7FF;
Cart.Emu.PPU_AddressBus &= 0xFF00;
Cart.Emu.PPU_AddressBus |= Cart.Emu.VRAM[Address];
}
}
return (byte)Cart.Emu.PPU_AddressBus;
}
public override ushort MirrorNametable(ushort Address)
{
if (!Cart.AlternativeNametableArrangement)
{
if (Mapper_4_NametableMirroring) //horizontal
{
return (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11
}
else //vertical
{
return (ushort)(Address & 0x37FF); // mask away $0800
}
}
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
if (Cart.PRGVRAM != null)
{
foreach (Byte b in Cart.PRGVRAM) { State.Add(b); }
}
State.Add(Mapper_4_8000);
State.Add(Mapper_4_BankA);
State.Add(Mapper_4_Bank8C);
State.Add(Mapper_4_CHR_2K0);
State.Add(Mapper_4_CHR_2K8);
State.Add(Mapper_4_CHR_1K0);
State.Add(Mapper_4_CHR_1K4);
State.Add(Mapper_4_CHR_1K8);
State.Add(Mapper_4_CHR_1KC);
State.Add(Mapper_4_IRQLatch);
State.Add(Mapper_4_IRQCounter);
State.Add((byte)(Mapper_4_EnableIRQ ? 1 : 0));
State.Add((byte)(Mapper_4_ReloadIRQCounter ? 1 : 0));
State.Add((byte)(Mapper_4_NametableMirroring ? 1 : 0));
State.Add(Mapper_4_PRGRAMProtect);
State.Add(Mapper_4_M2Filter);
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
if (Cart.PRGVRAM != null)
{
for (int i = 0; i < Cart.PRGVRAM.Length; i++) { Cart.PRGVRAM[i] = State[p++]; }
}
Mapper_4_8000 = State[p++];
Mapper_4_BankA = State[p++];
Mapper_4_Bank8C = State[p++];
Mapper_4_CHR_2K0 = State[p++];
Mapper_4_CHR_2K8 = State[p++];
Mapper_4_CHR_1K0 = State[p++];
Mapper_4_CHR_1K4 = State[p++];
Mapper_4_CHR_1K8 = State[p++];
Mapper_4_CHR_1KC = State[p++];
Mapper_4_IRQLatch = State[p++];
Mapper_4_IRQCounter = State[p++];
Mapper_4_EnableIRQ = (State[p++] & 1) == 1;
Mapper_4_ReloadIRQCounter = (State[p++] & 1) == 1;
Mapper_4_NametableMirroring = (State[p++] & 1) == 1;
Mapper_4_PRGRAMProtect = State[p++];
Mapper_4_M2Filter = State[p++];
exitIndex = p;
}
public override void PPUClock()
{
// if bit 12 of the ppu address bus (A12) changes:
if (!Cart.Emu.PPU_A12_Prev && ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) != 0) && Mapper_4_M2Filter == 3)
{
if (Mapper_4_ReloadIRQCounter)
{
// If we're reloading the IRQ counter
Mapper_4_IRQCounter = Mapper_4_IRQLatch; // The latch is the reset value.
Mapper_4_ReloadIRQCounter = false;
if (Mapper_4_IRQCounter == 0) // if the latch is set to 0, you need to enable the IRQ.
{
if (Mapper_4_EnableIRQ) // if setting the value to zero, run an IRQ
{
Cart.Emu.IRQ_LevelDetector = true;
}
}
}
else
{
// decrement the counter
Mapper_4_IRQCounter--;
if (Mapper_4_IRQCounter == 0) // if decrementing the counter moved it to 0...
{
if (Mapper_4_EnableIRQ) // and the MMC3 IRQ is enabled...
{
Cart.Emu.IRQ_LevelDetector = true; // Run an IRQ!
}
}
else if (Mapper_4_IRQCounter == 255) // if the counter underflows...
{
Mapper_4_IRQCounter = Mapper_4_IRQLatch; // reset the irq counter
if (Mapper_4_IRQCounter == 0) // if the latch is set to 0, you need to enable the IRQ... again
{
if (Mapper_4_EnableIRQ)
{
Cart.Emu.IRQ_LevelDetector = true;
}
}
}
}
}
if ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) != 0)
{
Mapper_4_M2Filter = 0;
}
}
public override void CPUClockRise()
{
if ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) == 0)
{
if (Mapper_4_M2Filter < 3)
{
Mapper_4_M2Filter++;
}
}
}
}
}
================================================
FILE: mappers/Mapper_NROM.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_NROM : Mapper
{
// ines Mapper 0
}
}
================================================
FILE: mappers/Mapper_NULL.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_NULL : Mapper
{
// There is not a cartridge inserted in the console.
public override void FetchPRG(ushort Address, bool Observe)
{
dataPinsAreNotFloating = false;
// the data pins are always floating. There's no cartridge inserted!
return;
}
public override byte FetchCHR(ushort Address, bool Observe)
{
// there's no cartridge. TODO: Look into this. Supposedly this would likely be the lower 8 bits of the address bus, but CIRAM enable is also floating.
return 0;
}
public override ushort MirrorNametable(ushort Address)
{
return Address;
}
public override List SaveMapperRegisters()
{
List State = new List();
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
exitIndex = p;
}
}
}
================================================
FILE: mappers/Mapper_UxROM.cs
================================================
using System;
using System.Collections.Generic;
namespace TriCNES.mappers
{
public class Mapper_UxROM : Mapper
{
// ines Mapper 2
public byte Mapper_2_BankSelect;
public override void FetchPRG(ushort Address, bool Observe)
{
bool notFloating = false;
byte data = 0;
if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }
// Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.
if (Address >= 0x8000)
{
notFloating = true;
if (Address >= 0xC000)
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[Cart.PRGROM.Length - 0x4000 + tempo];
}
else
{
ushort tempo = (ushort)(Address & 0x3FFF);
data = Cart.PRGROM[0x4000 * (Mapper_2_BankSelect & 0x0F) + tempo];
}
}
if (notFloating)
{
EndFetchPRG(Observe, data);
}
return;
}
public override void StorePRG(ushort Address, byte Input)
{
if (Address >= 0x8000)
{
Mapper_2_BankSelect = (byte)(Input & 0xF);
}
}
public override List SaveMapperRegisters()
{
List State = new List();
foreach (Byte b in Cart.PRGRAM) { State.Add(b); }
foreach (Byte b in Cart.CHRRAM) { State.Add(b); }
State.Add(Mapper_2_BankSelect);
return State;
}
public override void LoadMapperRegisters(List State, int startIndex, out int exitIndex)
{
int p = startIndex;
for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }
for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }
Mapper_2_BankSelect = State[p++];
exitIndex = p;
}
}
}
================================================
FILE: packages.config
================================================