Debugger: Added basic tilemap viewer
This commit is contained in:
parent
b9321f66f7
commit
706ef2f6e4
25 changed files with 1249 additions and 35 deletions
|
@ -267,9 +267,17 @@ void Console::ProcessWorkRamRead(uint32_t addr, uint8_t value)
|
|||
_debugger->ProcessWorkRamRead(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Console::ProcessWorkRamWrite(uint32_t addr, uint8_t value)
|
||||
{
|
||||
if(_debugger) {
|
||||
_debugger->ProcessWorkRamWrite(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Console::ProcessPpuCycle()
|
||||
{
|
||||
if(_debugger) {
|
||||
_debugger->ProcessPpuCycle();
|
||||
}
|
||||
}
|
|
@ -80,4 +80,5 @@ public:
|
|||
void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType);
|
||||
void ProcessWorkRamRead(uint32_t addr, uint8_t value);
|
||||
void ProcessWorkRamWrite(uint32_t addr, uint8_t value);
|
||||
void ProcessPpuCycle();
|
||||
};
|
|
@ -61,6 +61,7 @@
|
|||
<ClInclude Include="Cpu.h" />
|
||||
<ClInclude Include="DummyCpu.h" />
|
||||
<ClInclude Include="ExpressionEvaluator.h" />
|
||||
<ClInclude Include="PpuTools.h" />
|
||||
<ClInclude Include="RegisterHandlerB.h" />
|
||||
<ClInclude Include="CpuTypes.h" />
|
||||
<ClInclude Include="Debugger.h" />
|
||||
|
@ -137,6 +138,7 @@
|
|||
<ClCompile Include="MessageManager.cpp" />
|
||||
<ClCompile Include="NotificationManager.cpp" />
|
||||
<ClCompile Include="Ppu.cpp" />
|
||||
<ClCompile Include="PpuTools.cpp" />
|
||||
<ClCompile Include="SNES_SPC.cpp" />
|
||||
<ClCompile Include="SNES_SPC_misc.cpp" />
|
||||
<ClCompile Include="SNES_SPC_state.cpp" />
|
||||
|
|
|
@ -197,6 +197,9 @@
|
|||
<ClInclude Include="Breakpoint.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PpuTools.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -306,6 +309,7 @@
|
|||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BreakpointManager.cpp" />
|
||||
<ClCompile Include="PpuTools.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SNES">
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "CodeDataLogger.h"
|
||||
#include "Disassembler.h"
|
||||
#include "BreakpointManager.h"
|
||||
#include "PpuTools.h"
|
||||
#include "ExpressionEvaluator.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
|
@ -31,6 +32,7 @@ Debugger::Debugger(shared_ptr<Console> console)
|
|||
_traceLogger.reset(new TraceLogger(this, _memoryManager));
|
||||
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, console->GetCartridge()));
|
||||
_breakpointManager.reset(new BreakpointManager(this));
|
||||
_ppuTools.reset(new PpuTools(_console.get(), _ppu.get()));
|
||||
_cpuStepCount = 0;
|
||||
|
||||
string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_console->GetCartridge()->GetRomInfo().RomPath, false) + ".cdl");
|
||||
|
@ -84,10 +86,10 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType
|
|||
_cpuStepCount--;
|
||||
}
|
||||
|
||||
if(value == 0x00 || value == 0xCB) {
|
||||
//Break on BRK/WAI
|
||||
/*if(value == 0x00 || value == 0xDB || value == 0x42) {
|
||||
//Break on BRK/STP/WDM
|
||||
_cpuStepCount = 0;
|
||||
}
|
||||
}*/
|
||||
} else if(type == MemoryOperationType::ExecOperand) {
|
||||
if(addressInfo.Type == SnesMemoryType::PrgRom && addressInfo.Address >= 0) {
|
||||
_codeDataLogger->SetFlags(addressInfo.Address, CdlFlags::Code | (state.PS & (CdlFlags::IndexMode8 | CdlFlags::MemoryMode8)));
|
||||
|
@ -142,6 +144,13 @@ void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memo
|
|||
ProcessBreakConditions(operation, addressInfo);
|
||||
}
|
||||
|
||||
void Debugger::ProcessPpuCycle()
|
||||
{
|
||||
uint16_t scanline = _ppu->GetState().Scanline;
|
||||
uint16_t cycle = _ppu->GetState().Cycle;
|
||||
_ppuTools->UpdateViewers(scanline, cycle);
|
||||
}
|
||||
|
||||
void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo)
|
||||
{
|
||||
if(_breakpointManager->CheckBreakpoint(operation, addressInfo)) {
|
||||
|
@ -211,3 +220,8 @@ shared_ptr<BreakpointManager> Debugger::GetBreakpointManager()
|
|||
{
|
||||
return _breakpointManager;
|
||||
}
|
||||
|
||||
shared_ptr<PpuTools> Debugger::GetPpuTools()
|
||||
{
|
||||
return _ppuTools;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ class ExpressionEvaluator;
|
|||
class MemoryDumper;
|
||||
class Disassembler;
|
||||
class BreakpointManager;
|
||||
class PpuTools;
|
||||
struct DebugState;
|
||||
struct MemoryOperationInfo;
|
||||
struct AddressInfo;
|
||||
|
@ -37,6 +38,7 @@ private:
|
|||
shared_ptr<CodeDataLogger> _codeDataLogger;
|
||||
shared_ptr<Disassembler> _disassembler;
|
||||
shared_ptr<BreakpointManager> _breakpointManager;
|
||||
shared_ptr<PpuTools> _ppuTools;
|
||||
|
||||
unique_ptr<ExpressionEvaluator> _watchExpEval;
|
||||
|
||||
|
@ -55,6 +57,7 @@ public:
|
|||
|
||||
void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
|
||||
void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType);
|
||||
void ProcessPpuCycle();
|
||||
|
||||
void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo);
|
||||
|
||||
|
@ -70,4 +73,5 @@ public:
|
|||
shared_ptr<MemoryDumper> GetMemoryDumper();
|
||||
shared_ptr<Disassembler> GetDisassembler();
|
||||
shared_ptr<BreakpointManager> GetBreakpointManager();
|
||||
shared_ptr<PpuTools> GetPpuTools();
|
||||
};
|
|
@ -16,6 +16,7 @@ enum class ConsoleNotificationType
|
|||
ExecuteShortcut = 10,
|
||||
EmulationStopped = 11,
|
||||
BeforeEmulationStop = 12,
|
||||
ViewerRefresh = 13,
|
||||
};
|
||||
|
||||
class INotificationListener
|
||||
|
|
43
Core/Ppu.cpp
43
Core/Ppu.cpp
|
@ -56,12 +56,17 @@ uint32_t Ppu::GetFrameCount()
|
|||
|
||||
PpuState Ppu::GetState()
|
||||
{
|
||||
return {
|
||||
_cycle,
|
||||
_scanline,
|
||||
_frameCount,
|
||||
_overscanMode
|
||||
};
|
||||
PpuState state;
|
||||
state.Cycle = _cycle;
|
||||
state.Scanline = _scanline;
|
||||
state.FrameCount = _frameCount;
|
||||
state.OverscanMode = _overscanMode;
|
||||
state.BgMode = _bgMode;
|
||||
state.Layers[0] = _layerConfig[0];
|
||||
state.Layers[1] = _layerConfig[1];
|
||||
state.Layers[2] = _layerConfig[2];
|
||||
state.Layers[3] = _layerConfig[3];
|
||||
return state;
|
||||
}
|
||||
|
||||
void Ppu::Exec()
|
||||
|
@ -86,7 +91,7 @@ void Ppu::Exec()
|
|||
if(_regs->IsNmiEnabled()) {
|
||||
_console->GetCpu()->SetNmiFlag();
|
||||
}
|
||||
} else if(_scanline == 240 && _cycle == 0 && _frameCount & 0x01) {
|
||||
} else if(_scanline == 240 && _frameCount & 0x01) {
|
||||
//Skip 1 tick every other frame
|
||||
_cycle++;
|
||||
} else if(_scanline == 261) {
|
||||
|
@ -107,13 +112,14 @@ void Ppu::Exec()
|
|||
}
|
||||
}
|
||||
|
||||
_cycle++;
|
||||
_console->ProcessPpuCycle();
|
||||
|
||||
if(_regs->IsHorizontalIrqEnabled() && _cycle == _regs->GetHorizontalTimer() && (!_regs->IsVerticalIrqEnabled() || _scanline == _regs->GetVerticalTimer())) {
|
||||
//An IRQ will occur sometime just after the H Counter reaches the value set in $4207/$4208.
|
||||
_console->GetCpu()->SetIrqSource(IrqSource::Ppu);
|
||||
}
|
||||
|
||||
_cycle++;
|
||||
|
||||
|
||||
if(_cycle == 278 && _scanline <= (_overscanMode ? 239 : 224)) {
|
||||
if(_scanline != 0) {
|
||||
RenderScanline();
|
||||
|
@ -536,7 +542,7 @@ void Ppu::RenderTilemap()
|
|||
uint8_t baseYOffset = (realY + config.VScroll) & 0x07;
|
||||
|
||||
/* Tilemap offset based on the current row & tilemap size options */
|
||||
uint16_t addrVerticalScrollingOffset = config.VerticalMirroring ? ((row & 0x20) << (config.HorizontalMirroring ? 6 : 5)) : 0;
|
||||
uint16_t addrVerticalScrollingOffset = config.DoubleHeight ? ((row & 0x20) << (config.DoubleWidth ? 6 : 5)) : 0;
|
||||
|
||||
/* The start address for tiles on this row */
|
||||
uint16_t baseOffset = tilemapAddr + addrVerticalScrollingOffset + ((row & 0x1F) << 5);
|
||||
|
@ -570,7 +576,7 @@ void Ppu::RenderTilemap()
|
|||
baseYOffset = (realY + vScroll) & 0x07;
|
||||
} else {
|
||||
column = (realX + hScroll) >> (largeTileWidth ? 4 : 3);
|
||||
addr = (baseOffset + (column & 0x1F) + (config.HorizontalMirroring ? ((column & 0x20) << 5) : 0)) << 1;
|
||||
addr = (baseOffset + (column & 0x1F) + (config.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1;
|
||||
}
|
||||
|
||||
//Skip pixels that were filled by previous layers (or that don't match the priority level currently being processed)
|
||||
|
@ -625,9 +631,7 @@ void Ppu::RenderTilemap()
|
|||
uint16_t color = GetTilePixelColor<bpp>(pixelStart, shift);
|
||||
|
||||
if(color > 0) {
|
||||
/* Ignore palette bits for 256-color layers */
|
||||
uint16_t paletteColor;
|
||||
|
||||
if(bpp == 8 && directColorMode) {
|
||||
uint8_t palette = (_vram[addr + 1] >> 2) & 0x07;
|
||||
paletteColor = (
|
||||
|
@ -636,6 +640,7 @@ void Ppu::RenderTilemap()
|
|||
(((color & 0xC0) | ((palette & 0x04) << 3)) << 7)
|
||||
);
|
||||
} else {
|
||||
/* Ignore palette bits for 256-color layers */
|
||||
uint8_t palette = bpp == 8 ? 0 : (_vram[addr + 1] >> 2) & 0x07;
|
||||
uint16_t paletteRamOffset = basePaletteOffset + (palette * (1 << bpp) + color) * 2;
|
||||
paletteColor = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8);
|
||||
|
@ -698,9 +703,9 @@ void Ppu::ProcessOffsetMode(uint8_t x, uint16_t realX, uint16_t realY, uint16_t
|
|||
uint16_t offsetModeRow = (realY + vScroll) >> (largeTileHeight ? 4 : 3);
|
||||
uint16_t offsetModeColumn = (realX + hScroll) >> (largeTileWidth ? 4 : 3);
|
||||
|
||||
uint16_t addrVerticalScrollingOffset = config.VerticalMirroring ? ((offsetModeRow & 0x20) << (config.HorizontalMirroring ? 6 : 5)) : 0;
|
||||
uint16_t addrVerticalScrollingOffset = config.DoubleHeight ? ((offsetModeRow & 0x20) << (config.DoubleWidth ? 6 : 5)) : 0;
|
||||
uint16_t offsetModeBaseAddress = tilemapAddr + addrVerticalScrollingOffset + ((offsetModeRow & 0x1F) << 5);
|
||||
addr = (offsetModeBaseAddress + (offsetModeColumn & 0x1F) + (config.HorizontalMirroring ? ((offsetModeColumn & 0x20) << 5) : 0)) << 1;
|
||||
addr = (offsetModeBaseAddress + (offsetModeColumn & 0x1F) + (config.DoubleWidth ? ((offsetModeColumn & 0x20) << 5) : 0)) << 1;
|
||||
}
|
||||
|
||||
template<bool forMainScreen>
|
||||
|
@ -1266,7 +1271,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
|||
|
||||
case 0x2105:
|
||||
if(_bgMode != (value & 0x07)) {
|
||||
MessageManager::DisplayMessage("Debug", "Entering mode: " + std::to_string(value & 0x07));
|
||||
MessageManager::DisplayMessage("Debug", "Entering mode: " + std::to_string(value & 0x07) + " (SL: " + std::to_string(_scanline) + ")");
|
||||
}
|
||||
_bgMode = value & 0x07;
|
||||
_mode1Bg3Priority = (value & 0x08) != 0;
|
||||
|
@ -1290,8 +1295,8 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
|||
case 0x2107: case 0x2108: case 0x2109: case 0x210A:
|
||||
//BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC)
|
||||
_layerConfig[addr - 0x2107].TilemapAddress = (value & 0xFC) << 9;
|
||||
_layerConfig[addr - 0x2107].HorizontalMirroring = (value & 0x01) != 0;
|
||||
_layerConfig[addr - 0x2107].VerticalMirroring = (value & 0x02) != 0;
|
||||
_layerConfig[addr - 0x2107].DoubleWidth = (value & 0x01) != 0;
|
||||
_layerConfig[addr - 0x2107].DoubleHeight = (value & 0x02) != 0;
|
||||
break;
|
||||
|
||||
case 0x210B: case 0x210C:
|
||||
|
|
190
Core/PpuTools.cpp
Normal file
190
Core/PpuTools.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include "stdafx.h"
|
||||
#include "PpuTools.h"
|
||||
#include "Ppu.h"
|
||||
#include "DebugTypes.h"
|
||||
#include "Console.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
PpuTools::PpuTools(Console *console, Ppu *ppu)
|
||||
{
|
||||
_console = console;
|
||||
_ppu = ppu;
|
||||
}
|
||||
|
||||
uint16_t PpuTools::GetTilePixelColor(const uint8_t bpp, const uint16_t pixelStart, const uint8_t shift)
|
||||
{
|
||||
uint8_t *vram = _ppu->GetVideoRam();
|
||||
uint16_t color;
|
||||
if(bpp == 2) {
|
||||
color = (((vram[pixelStart + 0] >> shift) & 0x01) << 0);
|
||||
color |= (((vram[pixelStart + 1] >> shift) & 0x01) << 1);
|
||||
} else if(bpp == 4) {
|
||||
color = (((vram[pixelStart + 0] >> shift) & 0x01) << 0);
|
||||
color |= (((vram[pixelStart + 1] >> shift) & 0x01) << 1);
|
||||
color |= (((vram[pixelStart + 16] >> shift) & 0x01) << 2);
|
||||
color |= (((vram[pixelStart + 17] >> shift) & 0x01) << 3);
|
||||
} else if(bpp == 8) {
|
||||
color = (((vram[pixelStart + 0] >> shift) & 0x01) << 0);
|
||||
color |= (((vram[pixelStart + 1] >> shift) & 0x01) << 1);
|
||||
color |= (((vram[pixelStart + 16] >> shift) & 0x01) << 2);
|
||||
color |= (((vram[pixelStart + 17] >> shift) & 0x01) << 3);
|
||||
color |= (((vram[pixelStart + 32] >> shift) & 0x01) << 4);
|
||||
color |= (((vram[pixelStart + 33] >> shift) & 0x01) << 5);
|
||||
color |= (((vram[pixelStart + 48] >> shift) & 0x01) << 6);
|
||||
color |= (((vram[pixelStart + 49] >> shift) & 0x01) << 7);
|
||||
} else {
|
||||
throw std::runtime_error("unsupported bpp");
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
uint32_t PpuTools::ToArgb(uint16_t color)
|
||||
{
|
||||
uint8_t b = (color >> 10) << 3;
|
||||
uint8_t g = ((color >> 5) & 0x1F) << 3;
|
||||
uint8_t r = (color & 0x1F) << 3;
|
||||
|
||||
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
void PpuTools::BlendColors(uint8_t output[4], uint8_t input[4])
|
||||
{
|
||||
uint8_t alpha = input[3] + 1;
|
||||
uint8_t invertedAlpha = 256 - input[3];
|
||||
output[0] = (uint8_t)((alpha * input[0] + invertedAlpha * output[0]) >> 8);
|
||||
output[1] = (uint8_t)((alpha * input[1] + invertedAlpha * output[1]) >> 8);
|
||||
output[2] = (uint8_t)((alpha * input[2] + invertedAlpha * output[2]) >> 8);
|
||||
output[3] = 0xFF;
|
||||
}
|
||||
|
||||
void PpuTools::GetTilemap(GetTilemapOptions options, uint32_t* outBuffer)
|
||||
{
|
||||
static constexpr uint8_t layerBpp[8][4] = {
|
||||
{ 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 }
|
||||
};
|
||||
|
||||
PpuState state = _ppu->GetState();
|
||||
options.BgMode = state.BgMode;
|
||||
|
||||
uint16_t basePaletteOffset = 0;
|
||||
if(options.BgMode == 0) {
|
||||
basePaletteOffset = options.Layer * 64;
|
||||
}
|
||||
|
||||
uint8_t *vram = _ppu->GetVideoRam();
|
||||
uint8_t *cgram = _ppu->GetCgRam();
|
||||
LayerConfig layer = state.Layers[options.Layer];
|
||||
|
||||
uint16_t bgColor = (cgram[1] << 8) | cgram[0];
|
||||
for(int i = 0; i < 512 * 512; i++) {
|
||||
outBuffer[i] = ToArgb(bgColor);
|
||||
}
|
||||
|
||||
uint8_t bpp = layerBpp[options.BgMode][options.Layer];
|
||||
if(bpp == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool largeTileWidth = layer.LargeTiles || options.BgMode == 5 || options.BgMode == 6;
|
||||
bool largeTileHeight = layer.LargeTiles;
|
||||
|
||||
for(int row = 0; row < (layer.DoubleHeight ? 64 : 32); row++) {
|
||||
uint16_t addrVerticalScrollingOffset = layer.DoubleHeight ? ((row & 0x20) << (layer.DoubleWidth ? 6 : 5)) : 0;
|
||||
uint16_t baseOffset = (layer.TilemapAddress >> 1) + addrVerticalScrollingOffset + ((row & 0x1F) << 5);
|
||||
|
||||
for(int column = 0; column < (layer.DoubleWidth ? 64 : 32); column++) {
|
||||
uint16_t addr = (baseOffset + (column & 0x1F) + (layer.DoubleWidth ? ((column & 0x20) << 5) : 0)) << 1;
|
||||
|
||||
bool vMirror = (vram[addr + 1] & 0x80) != 0;
|
||||
bool hMirror = (vram[addr + 1] & 0x40) != 0;
|
||||
|
||||
uint16_t tileIndex = ((vram[addr + 1] & 0x03) << 8) | vram[addr];
|
||||
uint16_t tileStart = layer.ChrAddress + tileIndex * 8 * bpp;
|
||||
|
||||
if(largeTileWidth || largeTileHeight) {
|
||||
tileIndex = (
|
||||
tileIndex +
|
||||
(largeTileHeight ? ((row & 0x01) ? (vMirror ? 0 : 16) : (vMirror ? 16 : 0)) : 0) +
|
||||
(largeTileWidth ? ((column & 0x01) ? (hMirror ? 0 : 1) : (hMirror ? 1 : 0)) : 0)
|
||||
) & 0x3FF;
|
||||
}
|
||||
|
||||
for(int y = 0; y < 8; y++) {
|
||||
uint8_t yOffset = vMirror ? (7 - y) : y;
|
||||
uint16_t pixelStart = tileStart + yOffset * 2;
|
||||
|
||||
for(int x = 0; x < 8; x++) {
|
||||
uint8_t shift = hMirror ? x : (7 - x);
|
||||
uint16_t color = GetTilePixelColor(bpp, pixelStart, shift);
|
||||
if(color != 0) {
|
||||
uint16_t paletteColor;
|
||||
/*if(bpp == 8 && directColorMode) {
|
||||
uint8_t palette = (vram[addr + 1] >> 2) & 0x07;
|
||||
paletteColor = (
|
||||
(((color & 0x07) | (palette & 0x01)) << 1) |
|
||||
(((color & 0x38) | ((palette & 0x02) << 1)) << 3) |
|
||||
(((color & 0xC0) | ((palette & 0x04) << 3)) << 7)
|
||||
);
|
||||
} else {*/
|
||||
uint8_t palette = bpp == 8 ? 0 : (vram[addr + 1] >> 2) & 0x07;
|
||||
uint16_t paletteRamOffset = basePaletteOffset + (palette * (1 << bpp) + color) * 2;
|
||||
paletteColor = cgram[paletteRamOffset] | (cgram[paletteRamOffset + 1] << 8);
|
||||
//}
|
||||
|
||||
outBuffer[((row * 8) + y) * 512 + column * 8 + x] = ToArgb(paletteColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options.ShowTileGrid) {
|
||||
uint32_t gridColor = 0xA0AAAAFF;
|
||||
for(int i = 0; i < 512 * 512; i++) {
|
||||
if((i & 0x07) == 0x07 || (i & 0x0E00) == 0x0E00) {
|
||||
BlendColors((uint8_t*)&outBuffer[i], (uint8_t*)&gridColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options.ShowScrollOverlay) {
|
||||
uint32_t overlayColor = 0x40FFFFFF;
|
||||
for(int y = 0; y < 240; y++) {
|
||||
for(int x = 0; x < 256; x++) {
|
||||
int xPos = layer.HScroll + x;
|
||||
int yPos = layer.VScroll + y;
|
||||
|
||||
xPos &= layer.DoubleWidth ? 0x1FF : 0xFF;
|
||||
yPos &= layer.DoubleHeight ? 0x1FF : 0xFF;
|
||||
|
||||
if(x == 0 || y == 0 || x == 255 || y == 239) {
|
||||
outBuffer[(yPos << 9) | xPos] = 0xAFFFFFFF;
|
||||
} else {
|
||||
BlendColors((uint8_t*)&outBuffer[(yPos << 9) | xPos], (uint8_t*)&overlayColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PpuTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle)
|
||||
{
|
||||
//TODO Thread safety
|
||||
_updateTimings[viewerId] = (scanline << 16) | cycle;
|
||||
}
|
||||
|
||||
void PpuTools::RemoveViewer(uint32_t viewerId)
|
||||
{
|
||||
//TODO Thread safety
|
||||
_updateTimings.erase(viewerId);
|
||||
}
|
||||
|
||||
void PpuTools::UpdateViewers(uint16_t scanline, uint16_t cycle)
|
||||
{
|
||||
uint32_t currentCycle = (scanline << 16) | cycle;
|
||||
for(auto updateTiming : _updateTimings) {
|
||||
if(updateTiming.second == currentCycle) {
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first);
|
||||
}
|
||||
}
|
||||
}
|
28
Core/PpuTools.h
Normal file
28
Core/PpuTools.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
class Ppu;
|
||||
class Console;
|
||||
struct GetTilemapOptions;
|
||||
|
||||
class PpuTools
|
||||
{
|
||||
private:
|
||||
Ppu *_ppu;
|
||||
Console *_console;
|
||||
unordered_map<uint32_t, uint32_t> _updateTimings;
|
||||
|
||||
uint16_t GetTilePixelColor(const uint8_t bpp, const uint16_t pixelStart, const uint8_t shift);
|
||||
|
||||
uint32_t ToArgb(uint16_t color);
|
||||
void BlendColors(uint8_t output[4], uint8_t input[4]);
|
||||
|
||||
public:
|
||||
PpuTools(Console *console, Ppu* ppu);
|
||||
|
||||
void GetTilemap(GetTilemapOptions options, uint32_t *outBuffer);
|
||||
|
||||
void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle);
|
||||
void RemoveViewer(uint32_t viewerId);
|
||||
void UpdateViewers(uint16_t scanline, uint16_t cycle);
|
||||
};
|
|
@ -1,14 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
struct PpuState
|
||||
{
|
||||
uint16_t Cycle;
|
||||
uint16_t Scanline;
|
||||
uint32_t FrameCount;
|
||||
bool OverscanMode;
|
||||
};
|
||||
|
||||
struct LayerConfig
|
||||
{
|
||||
uint16_t TilemapAddress;
|
||||
|
@ -17,12 +9,23 @@ struct LayerConfig
|
|||
uint16_t HScroll;
|
||||
uint16_t VScroll;
|
||||
|
||||
bool HorizontalMirroring;
|
||||
bool VerticalMirroring;
|
||||
bool DoubleWidth;
|
||||
bool DoubleHeight;
|
||||
|
||||
bool LargeTiles;
|
||||
};
|
||||
|
||||
struct PpuState
|
||||
{
|
||||
uint16_t Cycle;
|
||||
uint16_t Scanline;
|
||||
uint32_t FrameCount;
|
||||
bool OverscanMode;
|
||||
|
||||
uint8_t BgMode;
|
||||
LayerConfig Layers[4];
|
||||
};
|
||||
|
||||
struct Mode7Config
|
||||
{
|
||||
int16_t Matrix[4];
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
|
@ -30,6 +32,8 @@
|
|||
#endif
|
||||
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
using std::unordered_set;
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::weak_ptr;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../Core/DebugTypes.h"
|
||||
#include "../Core/Breakpoint.h"
|
||||
#include "../Core/BreakpointManager.h"
|
||||
#include "../Core/PpuTools.h"
|
||||
|
||||
extern shared_ptr<Console> _console;
|
||||
|
||||
|
@ -59,4 +60,7 @@ extern "C"
|
|||
DllExport uint8_t __stdcall GetMemoryValue(SnesMemoryType type, uint32_t address) { return GetDebugger()->GetMemoryDumper()->GetMemoryValue(type, address); }
|
||||
DllExport void __stdcall SetMemoryValue(SnesMemoryType type, uint32_t address, uint8_t value) { return GetDebugger()->GetMemoryDumper()->SetMemoryValue(type, address, value); }
|
||||
DllExport void __stdcall SetMemoryValues(SnesMemoryType type, uint32_t address, uint8_t* data, int32_t length) { return GetDebugger()->GetMemoryDumper()->SetMemoryValues(type, address, data, length); }
|
||||
|
||||
DllExport void __stdcall GetTilemap(GetTilemapOptions options, uint32_t *buffer) { GetDebugger()->GetPpuTools()->GetTilemap(options, buffer); }
|
||||
DllExport void __stdcall SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle) { GetDebugger()->GetPpuTools()->SetViewerUpdateTiming(viewerId, scanline, cycle); }
|
||||
};
|
|
@ -34,6 +34,7 @@ namespace Mesen.GUI.Debugger
|
|||
case DebugWindow.Debugger: frm = new frmDebugger(); frm.Icon = Properties.Resources.Debugger; break;
|
||||
case DebugWindow.TraceLogger: frm = new frmTraceLogger(); frm.Icon = Properties.Resources.LogWindow; break;
|
||||
case DebugWindow.MemoryTools: frm = new frmMemoryTools(); frm.Icon = Properties.Resources.CheatCode; break;
|
||||
case DebugWindow.TilemapViewer: frm = new frmTilemapViewer(); frm.Icon = Properties.Resources.VideoOptions; break;
|
||||
}
|
||||
_openedWindows.Add(frm);
|
||||
frm.FormClosed += Debugger_FormClosed;
|
||||
|
@ -115,6 +116,7 @@ namespace Mesen.GUI.Debugger
|
|||
{
|
||||
Debugger,
|
||||
MemoryTools,
|
||||
TraceLogger
|
||||
TraceLogger,
|
||||
TilemapViewer
|
||||
}
|
||||
}
|
||||
|
|
71
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs
Normal file
71
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Mesen.GUI.Config;
|
||||
|
||||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
public partial class ctrlScanlineCycleSelect : UserControl
|
||||
{
|
||||
private static int _nextViewerId = 0;
|
||||
|
||||
private int _viewerId = 0;
|
||||
private int _scanline = 241;
|
||||
private int _cycle = 0;
|
||||
|
||||
public int Scanline { get { return _scanline; } }
|
||||
public int Cycle { get { return _cycle; } }
|
||||
public int ViewerId { get { return _viewerId; } }
|
||||
|
||||
public ctrlScanlineCycleSelect()
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewerId = GetNextViewerId();
|
||||
}
|
||||
|
||||
private int GetNextViewerId()
|
||||
{
|
||||
return _nextViewerId++;
|
||||
}
|
||||
|
||||
public void Initialize(int scanline, int cycle)
|
||||
{
|
||||
_scanline = scanline;
|
||||
_cycle = cycle;
|
||||
|
||||
this.nudScanline.Value = _scanline;
|
||||
this.nudCycle.Value = _cycle;
|
||||
|
||||
DebugApi.SetViewerUpdateTiming(_viewerId, _scanline, _cycle);
|
||||
}
|
||||
|
||||
public void RefreshSettings()
|
||||
{
|
||||
DebugApi.SetViewerUpdateTiming(_viewerId, _scanline, _cycle);
|
||||
}
|
||||
|
||||
private void SetUpdateScanlineCycle(int scanline, int cycle)
|
||||
{
|
||||
_scanline = scanline;
|
||||
_cycle = cycle;
|
||||
RefreshSettings();
|
||||
}
|
||||
|
||||
private void nudScanlineCycle_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetUpdateScanlineCycle((int)this.nudScanline.Value, (int)this.nudCycle.Value);
|
||||
}
|
||||
|
||||
private void btnReset_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.nudScanline.Value = 241;
|
||||
this.nudCycle.Value = 0;
|
||||
}
|
||||
}
|
||||
}
|
168
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.designer.cs
generated
Normal file
168
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.designer.cs
generated
Normal file
|
@ -0,0 +1,168 @@
|
|||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
partial class ctrlScanlineCycleSelect
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.flpRefreshTiming = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblShowFrameAt = new System.Windows.Forms.Label();
|
||||
this.nudScanline = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
this.lblCycle = new System.Windows.Forms.Label();
|
||||
this.nudCycle = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
this.btnReset = new System.Windows.Forms.Button();
|
||||
this.flpRefreshTiming.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// flpRefreshTiming
|
||||
//
|
||||
this.flpRefreshTiming.Controls.Add(this.lblShowFrameAt);
|
||||
this.flpRefreshTiming.Controls.Add(this.nudScanline);
|
||||
this.flpRefreshTiming.Controls.Add(this.lblCycle);
|
||||
this.flpRefreshTiming.Controls.Add(this.nudCycle);
|
||||
this.flpRefreshTiming.Controls.Add(this.btnReset);
|
||||
this.flpRefreshTiming.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flpRefreshTiming.Location = new System.Drawing.Point(0, 0);
|
||||
this.flpRefreshTiming.Name = "flpRefreshTiming";
|
||||
this.flpRefreshTiming.Size = new System.Drawing.Size(399, 28);
|
||||
this.flpRefreshTiming.TabIndex = 5;
|
||||
//
|
||||
// lblShowFrameAt
|
||||
//
|
||||
this.lblShowFrameAt.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblShowFrameAt.AutoSize = true;
|
||||
this.lblShowFrameAt.Location = new System.Drawing.Point(3, 8);
|
||||
this.lblShowFrameAt.Name = "lblShowFrameAt";
|
||||
this.lblShowFrameAt.Size = new System.Drawing.Size(135, 13);
|
||||
this.lblShowFrameAt.TabIndex = 0;
|
||||
this.lblShowFrameAt.Text = "Refresh viewer on scanline";
|
||||
//
|
||||
// nudScanline
|
||||
//
|
||||
this.nudScanline.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.nudScanline.DecimalPlaces = 0;
|
||||
this.nudScanline.Increment = new decimal(new int[] {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudScanline.Location = new System.Drawing.Point(144, 4);
|
||||
this.nudScanline.Maximum = new decimal(new int[] {
|
||||
260,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudScanline.MaximumSize = new System.Drawing.Size(10000, 20);
|
||||
this.nudScanline.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
-2147483648});
|
||||
this.nudScanline.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.nudScanline.Name = "nudScanline";
|
||||
this.nudScanline.Size = new System.Drawing.Size(52, 21);
|
||||
this.nudScanline.TabIndex = 5;
|
||||
this.nudScanline.Value = new decimal(new int[] {
|
||||
241,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudScanline.ValueChanged += new System.EventHandler(this.nudScanlineCycle_ValueChanged);
|
||||
//
|
||||
// lblCycle
|
||||
//
|
||||
this.lblCycle.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblCycle.AutoSize = true;
|
||||
this.lblCycle.Location = new System.Drawing.Point(202, 8);
|
||||
this.lblCycle.Name = "lblCycle";
|
||||
this.lblCycle.Size = new System.Drawing.Size(53, 13);
|
||||
this.lblCycle.TabIndex = 5;
|
||||
this.lblCycle.Text = "and cycle";
|
||||
//
|
||||
// nudCycle
|
||||
//
|
||||
this.nudCycle.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.nudCycle.DecimalPlaces = 0;
|
||||
this.nudCycle.Increment = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudCycle.Location = new System.Drawing.Point(261, 4);
|
||||
this.nudCycle.Maximum = new decimal(new int[] {
|
||||
340,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudCycle.MaximumSize = new System.Drawing.Size(10000, 20);
|
||||
this.nudCycle.Minimum = new decimal(new int[] {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudCycle.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.nudCycle.Name = "nudCycle";
|
||||
this.nudCycle.Size = new System.Drawing.Size(52, 21);
|
||||
this.nudCycle.TabIndex = 6;
|
||||
this.nudCycle.Value = new decimal(new int[] {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudCycle.ValueChanged += new System.EventHandler(this.nudScanlineCycle_ValueChanged);
|
||||
//
|
||||
// btnReset
|
||||
//
|
||||
this.btnReset.Location = new System.Drawing.Point(319, 3);
|
||||
this.btnReset.Name = "btnReset";
|
||||
this.btnReset.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnReset.TabIndex = 7;
|
||||
this.btnReset.Text = "Reset";
|
||||
this.btnReset.UseVisualStyleBackColor = true;
|
||||
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
|
||||
//
|
||||
// ctrlScanlineCycleSelect
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.flpRefreshTiming);
|
||||
this.Name = "ctrlScanlineCycleSelect";
|
||||
this.Size = new System.Drawing.Size(399, 28);
|
||||
this.flpRefreshTiming.ResumeLayout(false);
|
||||
this.flpRefreshTiming.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flpRefreshTiming;
|
||||
private System.Windows.Forms.Label lblShowFrameAt;
|
||||
private GUI.Controls.MesenNumericUpDown nudScanline;
|
||||
private System.Windows.Forms.Label lblCycle;
|
||||
private GUI.Controls.MesenNumericUpDown nudCycle;
|
||||
private System.Windows.Forms.Button btnReset;
|
||||
}
|
||||
}
|
120
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.resx
Normal file
120
UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
244
UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs
generated
Normal file
244
UI/Debugger/PpuViewer/frmTilemapViewer.Designer.cs
generated
Normal file
|
@ -0,0 +1,244 @@
|
|||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
partial class frmTilemapViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if(disposing && (components != null)) {
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.picTilemap = new Mesen.GUI.Controls.ctrlMesenPictureBox();
|
||||
this.btnLayer1 = new System.Windows.Forms.Button();
|
||||
this.btnLayer2 = new System.Windows.Forms.Button();
|
||||
this.btnLayer3 = new System.Windows.Forms.Button();
|
||||
this.btnLayer4 = new System.Windows.Forms.Button();
|
||||
this.ctrlScanlineCycleSelect = new Mesen.GUI.Debugger.Controls.ctrlScanlineCycleSelect();
|
||||
this.pnlTilemap = new System.Windows.Forms.Panel();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkShowScrollOverlay = new System.Windows.Forms.CheckBox();
|
||||
this.chkShowTileGrid = new System.Windows.Forms.CheckBox();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblLayer = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picTilemap)).BeginInit();
|
||||
this.pnlTilemap.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// picTilemap
|
||||
//
|
||||
this.picTilemap.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
this.picTilemap.Location = new System.Drawing.Point(0, 0);
|
||||
this.picTilemap.MinimumSize = new System.Drawing.Size(256, 256);
|
||||
this.picTilemap.Name = "picTilemap";
|
||||
this.picTilemap.Size = new System.Drawing.Size(512, 512);
|
||||
this.picTilemap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.picTilemap.TabIndex = 0;
|
||||
this.picTilemap.TabStop = false;
|
||||
this.picTilemap.DoubleClick += new System.EventHandler(this.picTilemap_DoubleClick);
|
||||
//
|
||||
// btnLayer1
|
||||
//
|
||||
this.btnLayer1.Location = new System.Drawing.Point(45, 3);
|
||||
this.btnLayer1.Name = "btnLayer1";
|
||||
this.btnLayer1.Size = new System.Drawing.Size(32, 22);
|
||||
this.btnLayer1.TabIndex = 1;
|
||||
this.btnLayer1.Text = "1";
|
||||
this.btnLayer1.UseVisualStyleBackColor = true;
|
||||
this.btnLayer1.Click += new System.EventHandler(this.btnLayer1_Click);
|
||||
//
|
||||
// btnLayer2
|
||||
//
|
||||
this.btnLayer2.Location = new System.Drawing.Point(83, 3);
|
||||
this.btnLayer2.Name = "btnLayer2";
|
||||
this.btnLayer2.Size = new System.Drawing.Size(32, 22);
|
||||
this.btnLayer2.TabIndex = 2;
|
||||
this.btnLayer2.Text = "2";
|
||||
this.btnLayer2.UseVisualStyleBackColor = true;
|
||||
this.btnLayer2.Click += new System.EventHandler(this.btnLayer2_Click);
|
||||
//
|
||||
// btnLayer3
|
||||
//
|
||||
this.btnLayer3.Location = new System.Drawing.Point(121, 3);
|
||||
this.btnLayer3.Name = "btnLayer3";
|
||||
this.btnLayer3.Size = new System.Drawing.Size(32, 22);
|
||||
this.btnLayer3.TabIndex = 3;
|
||||
this.btnLayer3.Text = "3";
|
||||
this.btnLayer3.UseVisualStyleBackColor = true;
|
||||
this.btnLayer3.Click += new System.EventHandler(this.btnLayer3_Click);
|
||||
//
|
||||
// btnLayer4
|
||||
//
|
||||
this.btnLayer4.Location = new System.Drawing.Point(159, 3);
|
||||
this.btnLayer4.Name = "btnLayer4";
|
||||
this.btnLayer4.Size = new System.Drawing.Size(32, 22);
|
||||
this.btnLayer4.TabIndex = 4;
|
||||
this.btnLayer4.Text = "4";
|
||||
this.btnLayer4.UseVisualStyleBackColor = true;
|
||||
this.btnLayer4.Click += new System.EventHandler(this.btnLayer4_Click);
|
||||
//
|
||||
// ctrlScanlineCycleSelect
|
||||
//
|
||||
this.ctrlScanlineCycleSelect.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.ctrlScanlineCycleSelect.Location = new System.Drawing.Point(0, 546);
|
||||
this.ctrlScanlineCycleSelect.Name = "ctrlScanlineCycleSelect";
|
||||
this.ctrlScanlineCycleSelect.Size = new System.Drawing.Size(667, 28);
|
||||
this.ctrlScanlineCycleSelect.TabIndex = 5;
|
||||
//
|
||||
// pnlTilemap
|
||||
//
|
||||
this.pnlTilemap.AutoScroll = true;
|
||||
this.pnlTilemap.Controls.Add(this.picTilemap);
|
||||
this.pnlTilemap.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.pnlTilemap.Location = new System.Drawing.Point(3, 31);
|
||||
this.pnlTilemap.MinimumSize = new System.Drawing.Size(512, 512);
|
||||
this.pnlTilemap.Name = "pnlTilemap";
|
||||
this.pnlTilemap.Size = new System.Drawing.Size(512, 512);
|
||||
this.pnlTilemap.TabIndex = 6;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.Controls.Add(this.pnlTilemap, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 2;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(667, 546);
|
||||
this.tableLayoutPanel1.TabIndex = 7;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 1;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkShowScrollOverlay, 0, 1);
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkShowTileGrid, 0, 0);
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(521, 3);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 3;
|
||||
this.tableLayoutPanel1.SetRowSpan(this.tableLayoutPanel2, 2);
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(143, 320);
|
||||
this.tableLayoutPanel2.TabIndex = 7;
|
||||
//
|
||||
// chkShowScrollOverlay
|
||||
//
|
||||
this.chkShowScrollOverlay.AutoSize = true;
|
||||
this.chkShowScrollOverlay.Location = new System.Drawing.Point(3, 26);
|
||||
this.chkShowScrollOverlay.Name = "chkShowScrollOverlay";
|
||||
this.chkShowScrollOverlay.Size = new System.Drawing.Size(117, 17);
|
||||
this.chkShowScrollOverlay.TabIndex = 1;
|
||||
this.chkShowScrollOverlay.Text = "Show scroll overlay";
|
||||
this.chkShowScrollOverlay.UseVisualStyleBackColor = true;
|
||||
this.chkShowScrollOverlay.Click += new System.EventHandler(this.chkShowScrollOverlay_Click);
|
||||
//
|
||||
// chkShowTileGrid
|
||||
//
|
||||
this.chkShowTileGrid.AutoSize = true;
|
||||
this.chkShowTileGrid.Location = new System.Drawing.Point(3, 3);
|
||||
this.chkShowTileGrid.Name = "chkShowTileGrid";
|
||||
this.chkShowTileGrid.Size = new System.Drawing.Size(89, 17);
|
||||
this.chkShowTileGrid.TabIndex = 0;
|
||||
this.chkShowTileGrid.Text = "Show tile grid";
|
||||
this.chkShowTileGrid.UseVisualStyleBackColor = true;
|
||||
this.chkShowTileGrid.Click += new System.EventHandler(this.chkShowTileGrid_Click);
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 6;
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.Controls.Add(this.btnLayer4, 4, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.btnLayer2, 2, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.btnLayer3, 3, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.btnLayer1, 1, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblLayer, 0, 0);
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 1;
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(205, 28);
|
||||
this.tableLayoutPanel3.TabIndex = 8;
|
||||
//
|
||||
// lblLayer
|
||||
//
|
||||
this.lblLayer.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblLayer.AutoSize = true;
|
||||
this.lblLayer.Location = new System.Drawing.Point(3, 7);
|
||||
this.lblLayer.Name = "lblLayer";
|
||||
this.lblLayer.Size = new System.Drawing.Size(36, 13);
|
||||
this.lblLayer.TabIndex = 5;
|
||||
this.lblLayer.Text = "Layer:";
|
||||
//
|
||||
// frmTilemapViewer
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(667, 574);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Controls.Add(this.ctrlScanlineCycleSelect);
|
||||
this.Name = "frmTilemapViewer";
|
||||
this.Text = "Tilemap Viewer";
|
||||
((System.ComponentModel.ISupportInitialize)(this.picTilemap)).EndInit();
|
||||
this.pnlTilemap.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel3.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private GUI.Controls.ctrlMesenPictureBox picTilemap;
|
||||
private System.Windows.Forms.Button btnLayer1;
|
||||
private System.Windows.Forms.Button btnLayer2;
|
||||
private System.Windows.Forms.Button btnLayer3;
|
||||
private System.Windows.Forms.Button btnLayer4;
|
||||
private Controls.ctrlScanlineCycleSelect ctrlScanlineCycleSelect;
|
||||
private System.Windows.Forms.Panel pnlTilemap;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.CheckBox chkShowTileGrid;
|
||||
private System.Windows.Forms.CheckBox chkShowScrollOverlay;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.Label lblLayer;
|
||||
}
|
||||
}
|
137
UI/Debugger/PpuViewer/frmTilemapViewer.cs
Normal file
137
UI/Debugger/PpuViewer/frmTilemapViewer.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
using Mesen.GUI.Forms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public partial class frmTilemapViewer : BaseForm
|
||||
{
|
||||
private NotificationListener _notifListener;
|
||||
private GetTilemapOptions _options;
|
||||
private DebugState _state;
|
||||
private byte[] _tilemapData;
|
||||
private Bitmap _tilemapImage;
|
||||
private bool _zoomed;
|
||||
|
||||
public frmTilemapViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if(!this.DesignMode) {
|
||||
_options.BgMode = 0;
|
||||
|
||||
_notifListener = new NotificationListener();
|
||||
_notifListener.OnNotification += OnNotificationReceived;
|
||||
|
||||
_tilemapImage = new Bitmap(512, 512, PixelFormat.Format32bppArgb);
|
||||
picTilemap.Image = _tilemapImage;
|
||||
|
||||
ctrlScanlineCycleSelect.Initialize(241, 0);
|
||||
|
||||
RefreshData();
|
||||
RefreshViewer();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnFormClosed(FormClosedEventArgs e)
|
||||
{
|
||||
base.OnFormClosed(e);
|
||||
_notifListener?.Dispose();
|
||||
}
|
||||
|
||||
private void OnNotificationReceived(NotificationEventArgs e)
|
||||
{
|
||||
switch(e.NotificationType) {
|
||||
case ConsoleNotificationType.ViewerRefresh:
|
||||
if(e.Parameter.ToInt32() == ctrlScanlineCycleSelect.ViewerId) {
|
||||
RefreshData();
|
||||
this.BeginInvoke((Action)(() => {
|
||||
this.RefreshViewer();
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshData()
|
||||
{
|
||||
_state = DebugApi.GetState();
|
||||
_tilemapData = DebugApi.GetTilemap(_options);
|
||||
}
|
||||
|
||||
private void RefreshViewer()
|
||||
{
|
||||
int mapWidth = _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256;
|
||||
int mapHeight = _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256;
|
||||
if(_tilemapImage.Width != mapWidth || _tilemapImage.Height != mapHeight) {
|
||||
_tilemapImage = new Bitmap(mapWidth, mapHeight, PixelFormat.Format32bppArgb);
|
||||
picTilemap.Image = _tilemapImage;
|
||||
}
|
||||
using(Graphics g = Graphics.FromImage(_tilemapImage)) {
|
||||
GCHandle handle = GCHandle.Alloc(_tilemapData, GCHandleType.Pinned);
|
||||
Bitmap source = new Bitmap(512, 512, 4 * 512, PixelFormat.Format32bppArgb, handle.AddrOfPinnedObject());
|
||||
try {
|
||||
g.DrawImage(source, 0, 0);
|
||||
} finally {
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateMapSize();
|
||||
picTilemap.Invalidate();
|
||||
}
|
||||
|
||||
private void UpdateMapSize()
|
||||
{
|
||||
int mapWidth = _state.Ppu.Layers[_options.Layer].DoubleWidth ? 512 : 256;
|
||||
int mapHeight = _state.Ppu.Layers[_options.Layer].DoubleHeight ? 512 : 256;
|
||||
picTilemap.Width = _zoomed ? mapWidth * 2 : mapWidth;
|
||||
picTilemap.Height = _zoomed ? mapHeight * 2 : mapHeight;
|
||||
}
|
||||
|
||||
private void btnLayer1_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.Layer = 0;
|
||||
}
|
||||
|
||||
private void btnLayer2_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.Layer = 1;
|
||||
}
|
||||
|
||||
private void btnLayer3_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.Layer = 2;
|
||||
}
|
||||
|
||||
private void btnLayer4_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.Layer = 3;
|
||||
}
|
||||
|
||||
private void picTilemap_DoubleClick(object sender, EventArgs e)
|
||||
{
|
||||
_zoomed = !_zoomed;
|
||||
UpdateMapSize();
|
||||
}
|
||||
|
||||
private void chkShowTileGrid_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.ShowTileGrid = chkShowTileGrid.Checked;
|
||||
}
|
||||
|
||||
private void chkShowScrollOverlay_Click(object sender, EventArgs e)
|
||||
{
|
||||
_options.ShowScrollOverlay = chkShowScrollOverlay.Checked;
|
||||
}
|
||||
}
|
||||
}
|
123
UI/Debugger/PpuViewer/frmTilemapViewer.resx
Normal file
123
UI/Debugger/PpuViewer/frmTilemapViewer.resx
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
13
UI/Forms/frmMain.Designer.cs
generated
13
UI/Forms/frmMain.Designer.cs
generated
|
@ -39,6 +39,7 @@
|
|||
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuMemoryTools = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTilemapViewer = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuMain.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
|
@ -86,7 +87,8 @@
|
|||
this.toolStripMenuItem1,
|
||||
this.mnuDebugger,
|
||||
this.mnuMemoryTools,
|
||||
this.mnuTraceLogger});
|
||||
this.mnuTraceLogger,
|
||||
this.mnuTilemapViewer});
|
||||
this.debugToolStripMenuItem.Name = "debugToolStripMenuItem";
|
||||
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 20);
|
||||
this.debugToolStripMenuItem.Text = "Debug";
|
||||
|
@ -144,6 +146,14 @@
|
|||
this.mnuTraceLogger.Text = "Trace Logger";
|
||||
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
|
||||
//
|
||||
// mnuTilemapViewer
|
||||
//
|
||||
this.mnuTilemapViewer.Image = global::Mesen.GUI.Properties.Resources.VideoOptions;
|
||||
this.mnuTilemapViewer.Name = "mnuTilemapViewer";
|
||||
this.mnuTilemapViewer.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuTilemapViewer.Text = "Tilemap Viewer";
|
||||
this.mnuTilemapViewer.Click += new System.EventHandler(this.mnuTilemapViewer_Click);
|
||||
//
|
||||
// frmMain
|
||||
//
|
||||
this.AllowDrop = true;
|
||||
|
@ -176,5 +186,6 @@
|
|||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuRun100Instructions;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuMemoryTools;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuTilemapViewer;
|
||||
}
|
||||
}
|
|
@ -73,6 +73,11 @@ namespace Mesen.GUI.Forms
|
|||
DebugWindowManager.OpenDebugWindow(DebugWindow.MemoryTools);
|
||||
}
|
||||
|
||||
private void mnuTilemapViewer_Click(object sender, EventArgs e)
|
||||
{
|
||||
DebugWindowManager.OpenDebugWindow(DebugWindow.TilemapViewer);
|
||||
}
|
||||
|
||||
private void mnuStep_Click(object sender, EventArgs e)
|
||||
{
|
||||
DebugApi.Step(1);
|
||||
|
|
|
@ -70,6 +70,16 @@ namespace Mesen.GUI
|
|||
DebugApi.GetMemoryStateWrapper(type, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
[DllImport(DllPath, EntryPoint = "GetTilemap")] private static extern void GetTilemapWrapper(GetTilemapOptions options, [In, Out] byte[] buffer);
|
||||
public static byte[] GetTilemap(GetTilemapOptions options)
|
||||
{
|
||||
byte[] buffer = new byte[512*512*4];
|
||||
DebugApi.GetTilemapWrapper(options, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
[DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle);
|
||||
}
|
||||
|
||||
public enum SnesMemoryType
|
||||
|
@ -112,14 +122,47 @@ namespace Mesen.GUI
|
|||
public UInt16 Cycle;
|
||||
public UInt16 Scanline;
|
||||
public UInt32 FrameCount;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool OverscanMode;
|
||||
|
||||
public byte BgMode;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public LayerConfig[] Layers;
|
||||
};
|
||||
|
||||
public struct LayerConfig
|
||||
{
|
||||
public UInt16 TilemapAddress;
|
||||
public UInt16 ChrAddress;
|
||||
|
||||
public UInt16 HScroll;
|
||||
public UInt16 VScroll;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DoubleWidth;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool DoubleHeight;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool LargeTiles;
|
||||
}
|
||||
|
||||
public struct DebugState
|
||||
{
|
||||
public CpuState Cpu;
|
||||
public PpuState Ppu;
|
||||
}
|
||||
|
||||
public struct GetTilemapOptions
|
||||
{
|
||||
public byte BgMode;
|
||||
public byte Layer;
|
||||
|
||||
public byte Bpp;
|
||||
public Int32 TilemapAddr;
|
||||
public Int32 ChrAddr;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowTileGrid;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowScrollOverlay;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct InteropTraceLoggerOptions
|
||||
{
|
||||
|
|
|
@ -22,7 +22,10 @@ namespace Mesen.GUI
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
EmuApi.UnregisterNotificationCallback(_notificationListener);
|
||||
if(_notificationListener != IntPtr.Zero) {
|
||||
EmuApi.UnregisterNotificationCallback(_notificationListener);
|
||||
_notificationListener = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessNotification(int type, IntPtr parameter)
|
||||
|
@ -57,5 +60,6 @@ namespace Mesen.GUI
|
|||
ExecuteShortcut = 10,
|
||||
EmulationStopped = 11,
|
||||
BeforeEmulationStop = 12,
|
||||
ViewerRefresh = 13,
|
||||
}
|
||||
}
|
||||
|
|
18
UI/UI.csproj
18
UI/UI.csproj
|
@ -374,6 +374,18 @@
|
|||
<Compile Include="Debugger\frmMemoryTools.designer.cs">
|
||||
<DependentUpon>frmMemoryTools.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\PpuViewer\ctrlScanlineCycleSelect.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\PpuViewer\ctrlScanlineCycleSelect.designer.cs">
|
||||
<DependentUpon>ctrlScanlineCycleSelect.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\PpuViewer\frmTilemapViewer.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\PpuViewer\frmTilemapViewer.Designer.cs">
|
||||
<DependentUpon>frmTilemapViewer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\frmTraceLogger.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -508,6 +520,12 @@
|
|||
<EmbeddedResource Include="Debugger\frmMemoryTools.resx">
|
||||
<DependentUpon>frmMemoryTools.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\PpuViewer\ctrlScanlineCycleSelect.resx">
|
||||
<DependentUpon>ctrlScanlineCycleSelect.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\PpuViewer\frmTilemapViewer.resx">
|
||||
<DependentUpon>frmTilemapViewer.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\frmTraceLogger.resx">
|
||||
<DependentUpon>frmTraceLogger.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
Loading…
Add table
Reference in a new issue