Debugger: Event Viewer - Added option to show NTSC borders
+ Ported most of Mesen-S' event viewer code to allow this to work
This commit is contained in:
parent
43811ae7ac
commit
8508b211cc
27 changed files with 1299 additions and 477 deletions
|
@ -48,6 +48,7 @@
|
|||
#include "NotificationManager.h"
|
||||
#include "HistoryViewer.h"
|
||||
#include "ConsolePauseHelper.h"
|
||||
#include "EventManager.h"
|
||||
#include "PgoUtilities.h"
|
||||
|
||||
Console::Console(shared_ptr<Console> master, EmulationSettings* initialSettings)
|
||||
|
@ -1482,6 +1483,15 @@ void Console::DebugSetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool up
|
|||
#endif
|
||||
}
|
||||
|
||||
void Console::DebugAddDebugEvent(DebugEventType type)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
if(_debugger) {
|
||||
_debugger->GetEventManager()->AddSpecialEvent(type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Console::DebugProcessRamOperation(MemoryOperationType type, uint16_t & addr, uint8_t & value)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
|
|
|
@ -39,6 +39,7 @@ enum class ScaleFilterType;
|
|||
enum class ConsoleFeatures;
|
||||
enum class DebugMemoryType;
|
||||
enum class EventType;
|
||||
enum class DebugEventType : uint8_t;
|
||||
enum class RamPowerOnState;
|
||||
|
||||
class Console : public std::enable_shared_from_this<Console>
|
||||
|
@ -233,6 +234,7 @@ public:
|
|||
void DebugProcessEvent(EventType type);
|
||||
void DebugProcessInterrupt(uint16_t cpuAddr, uint16_t destCpuAddr, bool forNmi);
|
||||
void DebugSetLastFramePpuScroll(uint16_t addr, uint8_t xScroll, bool updateHorizontalScrollOnly);
|
||||
void DebugAddDebugEvent(DebugEventType type);
|
||||
bool DebugProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value);
|
||||
void DebugProcessVramReadOperation(MemoryOperationType type, uint16_t addr, uint8_t &value);
|
||||
void DebugProcessVramWriteOperation(uint16_t addr, uint8_t &value);
|
||||
|
|
|
@ -537,6 +537,7 @@
|
|||
<ClInclude Include="DummyCpu.h" />
|
||||
<ClInclude Include="Eeprom24C01.h" />
|
||||
<ClInclude Include="Eeprom24C02.h" />
|
||||
<ClInclude Include="EventManager.h" />
|
||||
<ClInclude Include="FaridSlrom.h" />
|
||||
<ClInclude Include="FaridUnrom.h" />
|
||||
<ClInclude Include="FdsSystemActionManager.h" />
|
||||
|
@ -970,6 +971,7 @@
|
|||
<ClCompile Include="BatteryManager.cpp" />
|
||||
<ClCompile Include="DebugHud.cpp" />
|
||||
<ClCompile Include="DrawRectangleCommand.h" />
|
||||
<ClCompile Include="EventManager.cpp" />
|
||||
<ClCompile Include="FceuxMovie.cpp" />
|
||||
<ClCompile Include="FdsLoader.cpp" />
|
||||
<ClCompile Include="HdAudioDevice.cpp" />
|
||||
|
|
|
@ -1487,6 +1487,9 @@
|
|||
<ClInclude Include="BaseEeprom24C0X.h">
|
||||
<Filter>Nes\Mappers\Bandai</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EventManager.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1786,5 +1789,8 @@
|
|||
<ClCompile Include="PerformanceTracker.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EventManager.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -31,6 +31,7 @@
|
|||
#include "DebugHud.h"
|
||||
#include "DummyCpu.h"
|
||||
#include "PerformanceTracker.h"
|
||||
#include "EventManager.h"
|
||||
|
||||
const int Debugger::BreakpointTypeCount;
|
||||
string Debugger::_disassemblerOutput = "";
|
||||
|
@ -57,6 +58,7 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> cpu, shared_ptr<
|
|||
_memoryAccessCounter.reset(new MemoryAccessCounter(this));
|
||||
_profiler.reset(new Profiler(this));
|
||||
_performanceTracker.reset(new PerformanceTracker(console));
|
||||
_eventManager.reset(new EventManager(this, cpu.get(), ppu.get(), _console->GetSettings()));
|
||||
_traceLogger.reset(new TraceLogger(this, memoryManager, _labelManager));
|
||||
|
||||
_bpExpEval.reset(new ExpressionEvaluator(this));
|
||||
|
@ -413,7 +415,7 @@ bool Debugger::ProcessBreakpoints(BreakpointType type, OperationInfo &operationI
|
|||
}
|
||||
|
||||
if(needMark && allowMark) {
|
||||
AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId);
|
||||
_eventManager->AddDebugEvent(DebugEventType::Breakpoint, operationInfo.Address, (uint8_t)operationInfo.Value, markBreakpointId);
|
||||
}
|
||||
|
||||
if(needBreak && allowBreak) {
|
||||
|
@ -700,7 +702,7 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
//Used to flag the data in the CDL file
|
||||
isDmcRead = true;
|
||||
type = MemoryOperationType::Read;
|
||||
AddDebugEvent(DebugEventType::DmcDmaRead, addr, value);
|
||||
_eventManager->AddDebugEvent(DebugEventType::DmcDmaRead, addr, value);
|
||||
}
|
||||
|
||||
ProcessCpuOperation(addr, value, type);
|
||||
|
@ -912,12 +914,12 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
if(addr >= 0x2000 && addr <= 0x3FFF) {
|
||||
if((addr & 0x07) == 5 || (addr & 0x07) == 6) {
|
||||
GetState(&_debugState, false);
|
||||
AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value, -1, _debugState.PPU.State.WriteToggle ? 1 : 0);
|
||||
_eventManager->AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value, -1, _debugState.PPU.State.WriteToggle ? 1 : 0);
|
||||
} else {
|
||||
AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value);
|
||||
_eventManager->AddDebugEvent(DebugEventType::PpuRegisterWrite, addr, value);
|
||||
}
|
||||
} else if(addr >= 0x4018 && _mapper->IsWriteRegister(addr)) {
|
||||
AddDebugEvent(DebugEventType::MapperRegisterWrite, addr, value);
|
||||
_eventManager->AddDebugEvent(DebugEventType::MapperRegisterWrite, addr, value);
|
||||
}
|
||||
|
||||
if(_frozenAddresses[addr]) {
|
||||
|
@ -925,9 +927,9 @@ bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uin
|
|||
}
|
||||
} else if(type == MemoryOperationType::Read) {
|
||||
if(addr >= 0x2000 && addr <= 0x3FFF) {
|
||||
AddDebugEvent(DebugEventType::PpuRegisterRead, addr, value);
|
||||
_eventManager->AddDebugEvent(DebugEventType::PpuRegisterRead, addr, value);
|
||||
} else if(addr >= 0x4018 && _mapper->IsReadRegister(addr)) {
|
||||
AddDebugEvent(DebugEventType::MapperRegisterRead, addr, value);
|
||||
_eventManager->AddDebugEvent(DebugEventType::MapperRegisterRead, addr, value);
|
||||
}
|
||||
} else if(type == MemoryOperationType::ExecOpCode) {
|
||||
if(!_needRewind) {
|
||||
|
@ -1316,6 +1318,11 @@ shared_ptr<PerformanceTracker> Debugger::GetPerformanceTracker()
|
|||
return _performanceTracker;
|
||||
}
|
||||
|
||||
shared_ptr<EventManager> Debugger::GetEventManager()
|
||||
{
|
||||
return _eventManager;
|
||||
}
|
||||
|
||||
bool Debugger::IsExecutionStopped()
|
||||
{
|
||||
return _executionStopped || _console->IsExecutionStopped();
|
||||
|
@ -1616,59 +1623,19 @@ void Debugger::ProcessEvent(EventType type)
|
|||
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
|
||||
_ppu->DebugUpdateFrameBuffer(CheckFlag(DebuggerFlags::PpuShowPreviousFrame));
|
||||
}
|
||||
_prevDebugEvents = _debugEvents;
|
||||
_debugEvents.clear();
|
||||
|
||||
_eventManager->ClearFrameEvents();
|
||||
} else if(type == EventType::Nmi) {
|
||||
AddDebugEvent(DebugEventType::Nmi);
|
||||
_eventManager->AddDebugEvent(DebugEventType::Nmi);
|
||||
} else if(type == EventType::Irq) {
|
||||
AddDebugEvent(DebugEventType::Irq);
|
||||
_eventManager->AddDebugEvent(DebugEventType::Irq);
|
||||
} else if(type == EventType::SpriteZeroHit) {
|
||||
AddDebugEvent(DebugEventType::SpriteZeroHit);
|
||||
_eventManager->AddDebugEvent(DebugEventType::SpriteZeroHit);
|
||||
} else if(type == EventType::Reset) {
|
||||
_enableBreakOnUninitRead = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::AddDebugEvent(DebugEventType type, uint16_t address, uint8_t value, int16_t breakpointId, int8_t ppuLatch)
|
||||
{
|
||||
_debugEvents.push_back({
|
||||
(uint16_t)_ppu->GetCurrentCycle(),
|
||||
(int16_t)_ppu->GetCurrentScanline(),
|
||||
_cpu->GetDebugPC(),
|
||||
address,
|
||||
breakpointId,
|
||||
type,
|
||||
value,
|
||||
ppuLatch,
|
||||
});
|
||||
}
|
||||
|
||||
void Debugger::GetDebugEvents(uint32_t* pictureBuffer, DebugEventInfo *infoArray, uint32_t &maxEventCount, bool returnPreviousFrameData)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
|
||||
uint16_t *ppuBuffer = new uint16_t[PPU::PixelCount];
|
||||
uint32_t *palette = _console->GetSettings()->GetRgbPalette();
|
||||
_ppu->DebugCopyOutputBuffer(ppuBuffer);
|
||||
|
||||
for(int i = 0; i < PPU::PixelCount; i++) {
|
||||
pictureBuffer[i] = palette[ppuBuffer[i] & 0x3F];
|
||||
}
|
||||
|
||||
delete[] ppuBuffer;
|
||||
|
||||
vector<DebugEventInfo> &events = returnPreviousFrameData ? _prevDebugEvents : _debugEvents;
|
||||
uint32_t eventCount = std::min(maxEventCount, (uint32_t)events.size());
|
||||
memcpy(infoArray, events.data(), eventCount * sizeof(DebugEventInfo));
|
||||
maxEventCount = eventCount;
|
||||
}
|
||||
|
||||
uint32_t Debugger::GetDebugEventCount(bool returnPreviousFrameData)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
return (uint32_t)(returnPreviousFrameData ? _prevDebugEvents.size() : _debugEvents.size());
|
||||
}
|
||||
|
||||
uint32_t Debugger::GetScreenPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
return _ppu->GetPixel(x, y);
|
||||
|
|
|
@ -31,6 +31,7 @@ class Breakpoint;
|
|||
class CodeDataLogger;
|
||||
class ExpressionEvaluator;
|
||||
class DummyCpu;
|
||||
class EventManager;
|
||||
struct ExpressionData;
|
||||
|
||||
enum EvalResultType : int32_t;
|
||||
|
@ -53,6 +54,7 @@ private:
|
|||
shared_ptr<TraceLogger> _traceLogger;
|
||||
shared_ptr<Profiler> _profiler;
|
||||
shared_ptr<PerformanceTracker> _performanceTracker;
|
||||
shared_ptr<EventManager> _eventManager;
|
||||
unique_ptr<CodeRunner> _codeRunner;
|
||||
|
||||
shared_ptr<Console> _console;
|
||||
|
@ -140,9 +142,6 @@ private:
|
|||
|
||||
uint32_t _inputOverride[4];
|
||||
|
||||
vector<DebugEventInfo> _prevDebugEvents;
|
||||
vector<DebugEventInfo> _debugEvents;
|
||||
|
||||
private:
|
||||
bool ProcessBreakpoints(BreakpointType type, OperationInfo &operationInfo, bool allowBreak = true, bool allowMark = true);
|
||||
void ProcessAllBreakpoints(OperationInfo &operationInfo);
|
||||
|
@ -153,8 +152,6 @@ private:
|
|||
void ProcessStepConditions(uint16_t addr);
|
||||
bool SleepUntilResume(BreakSource source, uint32_t breakpointId = 0, BreakpointType bpType = BreakpointType::Global, uint16_t bpAddress = 0, uint8_t bpValue = 0, MemoryOperationType bpMemOpType = MemoryOperationType::Read);
|
||||
|
||||
void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
|
||||
|
||||
void UpdatePpuCyclesToProcess();
|
||||
void ResetStepState();
|
||||
|
||||
|
@ -236,6 +233,7 @@ public:
|
|||
shared_ptr<MemoryDumper> GetMemoryDumper();
|
||||
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
|
||||
shared_ptr<PerformanceTracker> GetPerformanceTracker();
|
||||
shared_ptr<EventManager> GetEventManager();
|
||||
|
||||
int32_t EvaluateExpression(string expression, EvalResultType &resultType, bool useCache);
|
||||
|
||||
|
@ -280,8 +278,5 @@ public:
|
|||
void ProcessPpuOperation(uint16_t addr, uint8_t &value, MemoryOperationType type);
|
||||
void ProcessEvent(EventType type);
|
||||
|
||||
void GetDebugEvents(uint32_t* pictureBuffer, DebugEventInfo *infoArray, uint32_t &maxEventCount, bool returnPreviousFrameData);
|
||||
uint32_t GetDebugEventCount(bool returnPreviousFrameData);
|
||||
|
||||
uint32_t GetScreenPixel(uint8_t x, uint8_t y);
|
||||
};
|
|
@ -166,13 +166,14 @@ enum class DebugEventType : uint8_t
|
|||
SpriteZeroHit,
|
||||
Breakpoint,
|
||||
DmcDmaRead,
|
||||
BgColorChange,
|
||||
};
|
||||
|
||||
struct DebugEventInfo
|
||||
{
|
||||
uint16_t Cycle;
|
||||
int16_t Scanline;
|
||||
uint16_t ProgramCounter;
|
||||
uint32_t ProgramCounter;
|
||||
uint16_t Address;
|
||||
int16_t BreakpointId;
|
||||
DebugEventType Type;
|
||||
|
|
284
Core/EventManager.cpp
Normal file
284
Core/EventManager.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
#include "stdafx.h"
|
||||
#include "EventManager.h"
|
||||
#include "DebuggerTypes.h"
|
||||
#include "CPU.h"
|
||||
#include "PPU.h"
|
||||
#include "Debugger.h"
|
||||
#include "DebugBreakHelper.h"
|
||||
#include "DefaultVideoFilter.h"
|
||||
|
||||
EventManager::EventManager(Debugger *debugger, CPU *cpu, PPU *ppu, EmulationSettings *settings)
|
||||
{
|
||||
_debugger = debugger;
|
||||
_cpu = cpu;
|
||||
_ppu = ppu;
|
||||
_settings = settings;
|
||||
|
||||
_ppuBuffer = new uint16_t[256*240];
|
||||
memset(_ppuBuffer, 0, 256*240 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
EventManager::~EventManager()
|
||||
{
|
||||
delete[] _ppuBuffer;
|
||||
}
|
||||
|
||||
void EventManager::AddSpecialEvent(DebugEventType type)
|
||||
{
|
||||
if(type == DebugEventType::BgColorChange) {
|
||||
AddDebugEvent(DebugEventType::BgColorChange, 0, _ppu->GetCurrentBgColor());
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::AddDebugEvent(DebugEventType type, uint16_t address, uint8_t value, int16_t breakpointId, int8_t ppuLatch)
|
||||
{
|
||||
_debugEvents.push_back({
|
||||
(uint16_t)_ppu->GetCurrentCycle(),
|
||||
(int16_t)_ppu->GetCurrentScanline(),
|
||||
_cpu->GetDebugPC(),
|
||||
address,
|
||||
breakpointId,
|
||||
type,
|
||||
value,
|
||||
ppuLatch,
|
||||
});
|
||||
}
|
||||
|
||||
void EventManager::GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount, bool getPreviousFrameData)
|
||||
{
|
||||
DebugBreakHelper breakHelper(_debugger);
|
||||
|
||||
vector<DebugEventInfo> &events = getPreviousFrameData ? _prevDebugEvents : _debugEvents;
|
||||
uint32_t eventCount = std::min(maxEventCount, (uint32_t)events.size());
|
||||
memcpy(eventArray, events.data(), eventCount * sizeof(DebugEventInfo));
|
||||
maxEventCount = eventCount;
|
||||
}
|
||||
|
||||
DebugEventInfo EventManager::GetEvent(int16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options)
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
|
||||
for(DebugEventInfo &evt : _sentEvents) {
|
||||
if(evt.Cycle == cycle && evt.Scanline == scanline) {
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
|
||||
DebugEventInfo empty = {};
|
||||
empty.ProgramCounter = 0xFFFFFFFF;
|
||||
return empty;
|
||||
}
|
||||
|
||||
uint32_t EventManager::GetEventCount(bool getPreviousFrameData)
|
||||
{
|
||||
DebugBreakHelper breakHelper(_debugger);
|
||||
return (uint32_t)(getPreviousFrameData ? _prevDebugEvents.size() : _debugEvents.size());
|
||||
}
|
||||
|
||||
void EventManager::ClearFrameEvents()
|
||||
{
|
||||
_prevDebugEvents = _debugEvents;
|
||||
_debugEvents.clear();
|
||||
AddDebugEvent(DebugEventType::BgColorChange, 0, _ppu->ReadPaletteRAM(0));
|
||||
}
|
||||
|
||||
void EventManager::DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options)
|
||||
{
|
||||
bool showEvent = false;
|
||||
uint32_t color = 0;
|
||||
switch(evt.Type) {
|
||||
case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; color = options.BreakpointColor; break;
|
||||
case DebugEventType::Irq: showEvent = options.ShowIrq; color = options.IrqColor; break;
|
||||
case DebugEventType::Nmi: showEvent = options.ShowNmi; color = options.NmiColor; break;
|
||||
case DebugEventType::DmcDmaRead: showEvent = options.ShowDmcDmaReads; color = options.DmcDmaReadColor; break;
|
||||
case DebugEventType::SpriteZeroHit: showEvent = options.ShowSpriteZeroHit; color = options.SpriteZeroHitColor; break;
|
||||
|
||||
case DebugEventType::MapperRegisterWrite:
|
||||
showEvent = options.ShowMapperRegisterWrites;
|
||||
color = options.MapperRegisterWriteColor;
|
||||
break;
|
||||
|
||||
case DebugEventType::MapperRegisterRead:
|
||||
showEvent = options.ShowMapperRegisterReads;
|
||||
color = options.MapperRegisterReadColor;
|
||||
break;
|
||||
|
||||
case DebugEventType::PpuRegisterWrite:
|
||||
showEvent = options.ShowPpuRegisterWrites[evt.Address & 0x07];
|
||||
color = options.PpuRegisterWriteColors[evt.Address & 0x07];
|
||||
break;
|
||||
|
||||
case DebugEventType::PpuRegisterRead:
|
||||
showEvent = options.ShowPpuRegisterReads[evt.Address & 0x07];
|
||||
color = options.PpuRegisterReadColors[evt.Address & 0x07];
|
||||
break;
|
||||
}
|
||||
|
||||
if(!showEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(drawBackground) {
|
||||
color = 0xFF000000 | ((color >> 1) & 0x7F7F7F);
|
||||
} else {
|
||||
_sentEvents.push_back(evt);
|
||||
color |= 0xFF000000;
|
||||
}
|
||||
|
||||
int iMin = drawBackground ? -2 : 0;
|
||||
int iMax = drawBackground ? 3 : 1;
|
||||
int jMin = drawBackground ? -2 : 0;
|
||||
int jMax = drawBackground ? 3 : 1;
|
||||
uint32_t y = std::min<uint32_t>((evt.Scanline + 1) * 2, _scanlineCount * 2);
|
||||
uint32_t x = evt.Cycle * 2;
|
||||
|
||||
for(int i = iMin; i <= iMax; i++) {
|
||||
for(int j = jMin; j <= jMax; j++) {
|
||||
int32_t pos = (y + i) * 341 * 2 + x + j;
|
||||
if(pos < 0 || pos >= 341 * 2 * (int)_scanlineCount * 2) {
|
||||
continue;
|
||||
}
|
||||
buffer[pos] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options)
|
||||
{
|
||||
DebugBreakHelper breakHelper(_debugger);
|
||||
auto lock = _lock.AcquireSafe();
|
||||
_snapshot.clear();
|
||||
|
||||
uint16_t cycle = _ppu->GetCurrentCycle();
|
||||
uint16_t scanline = _ppu->GetCurrentScanline() + 1;
|
||||
uint32_t key = (scanline << 9) + cycle;
|
||||
constexpr uint32_t size = 256 * 240;
|
||||
|
||||
if(scanline >= 240 || (scanline == 0 && cycle == 0)) {
|
||||
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(false), size * sizeof(uint16_t));
|
||||
} else {
|
||||
uint32_t offset = (256 * scanline);
|
||||
memcpy(_ppuBuffer, _ppu->GetScreenBuffer(false), offset * sizeof(uint16_t));
|
||||
memcpy(_ppuBuffer + offset, _ppu->GetScreenBuffer(true) + offset, (size - offset) * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
_snapshot = _debugEvents;
|
||||
_snapshotScanline = scanline;
|
||||
if(options.ShowPreviousFrameEvents && scanline != 0) {
|
||||
for(DebugEventInfo &evt : _prevDebugEvents) {
|
||||
uint32_t evtKey = (evt.Scanline << 9) + evt.Cycle;
|
||||
if(evtKey > key) {
|
||||
_snapshot.push_back(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PPUDebugState state;
|
||||
_ppu->GetState(state);
|
||||
_scanlineCount = state.ScanlineCount;
|
||||
return _scanlineCount;
|
||||
}
|
||||
|
||||
void EventManager::GetDisplayBuffer(uint32_t *buffer, EventViewerDisplayOptions options)
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
_sentEvents.clear();
|
||||
|
||||
for(int i = 0; i < 341 * 2 * (int)_scanlineCount * 2; i++) {
|
||||
buffer[i] = 0xFF555555;
|
||||
}
|
||||
|
||||
uint16_t *src = _ppuBuffer;
|
||||
uint32_t* pal = _settings->GetRgbPalette();
|
||||
for(uint32_t y = 0, len = 240*2; y < len; y++) {
|
||||
int rowOffset = (y + 2) * 341 * 2;
|
||||
|
||||
for(uint32_t x = 0; x < 256*2; x++) {
|
||||
int srcOffset = ((y >> 1) << 8) | (x >> 1);
|
||||
buffer[rowOffset + x + 1 * 2] = pal[src[srcOffset]];
|
||||
}
|
||||
}
|
||||
|
||||
if(options.ShowNtscBorders) {
|
||||
DrawNtscBorders(buffer);
|
||||
}
|
||||
|
||||
constexpr uint32_t currentScanlineColor = 0xFFFFFF55;
|
||||
uint32_t scanlineOffset = _snapshotScanline * 2 * 341 * 2;
|
||||
for(int i = 0; i < 341 * 2; i++) {
|
||||
if(_snapshotScanline != 0) {
|
||||
buffer[scanlineOffset + i] = currentScanlineColor;
|
||||
buffer[scanlineOffset + 341 * 2 + i] = currentScanlineColor;
|
||||
}
|
||||
}
|
||||
|
||||
for(DebugEventInfo &evt : _snapshot) {
|
||||
DrawEvent(evt, true, buffer, options);
|
||||
}
|
||||
for(DebugEventInfo &evt : _snapshot) {
|
||||
DrawEvent(evt, false, buffer, options);
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::DrawPixel(uint32_t *buffer, int32_t x, uint32_t y, uint32_t color)
|
||||
{
|
||||
if(x < 0) {
|
||||
x += 341;
|
||||
y--;
|
||||
} else if(x >= 341) {
|
||||
x -= 341;
|
||||
y++;
|
||||
}
|
||||
|
||||
buffer[y * 341 * 4 + x * 2] = color;
|
||||
buffer[y * 341 * 4 + x * 2 + 1] = color;
|
||||
buffer[y * 341 * 4 + 341*2 + x * 2] = color;
|
||||
buffer[y * 341 * 4 + 341*2 + x * 2 + 1] = color;
|
||||
}
|
||||
|
||||
void EventManager::DrawNtscBorders(uint32_t *buffer)
|
||||
{
|
||||
//Generate array of bg color for all pixels on the screen
|
||||
uint32_t currentPos = 0;
|
||||
uint8_t currentColor = 0;
|
||||
vector<uint8_t> bgColor;
|
||||
bgColor.resize(341 * 243);
|
||||
uint32_t* pal = _settings->GetRgbPalette();
|
||||
|
||||
for(DebugEventInfo &evt : _snapshot) {
|
||||
if(evt.Type == DebugEventType::BgColorChange) {
|
||||
uint32_t pos = ((evt.Scanline + 1) * 341) + evt.Cycle;
|
||||
if(pos >= currentPos && evt.Scanline < 242) {
|
||||
memset(bgColor.data() + currentPos, currentColor, pos - currentPos);
|
||||
currentColor = evt.Value;
|
||||
currentPos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(bgColor.data() + currentPos, currentColor, 341 * 243 - currentPos);
|
||||
|
||||
for(uint32_t y = 1; y < 241; y++) {
|
||||
//Pulse
|
||||
uint32_t basePos = y * 341;
|
||||
DrawPixel(buffer, -15, y, pal[bgColor[basePos - 16] & 0x30]);
|
||||
|
||||
//Left border
|
||||
for(int32_t x = 0; x < 15; x++) {
|
||||
DrawPixel(buffer, -x, y, pal[bgColor[basePos - x]]);
|
||||
}
|
||||
|
||||
//Right border
|
||||
for(int32_t x = 0; x < 11; x++) {
|
||||
DrawPixel(buffer, 257+x, y, pal[bgColor[basePos + 257 + x]]);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t y = 240; y < 242; y++) {
|
||||
//Bottom border
|
||||
uint32_t basePos = y * 341;
|
||||
DrawPixel(buffer, 326, y, pal[bgColor[basePos + 326] & 0x30]);
|
||||
for(int32_t x = 0; x < 282; x++) {
|
||||
DrawPixel(buffer, 327 + x, y, pal[bgColor[basePos + 327 + x]]);
|
||||
}
|
||||
}
|
||||
}
|
80
Core/EventManager.h
Normal file
80
Core/EventManager.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Types.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
|
||||
enum class DebugEventType : uint8_t;
|
||||
struct DebugEventInfo;
|
||||
struct EventViewerDisplayOptions;
|
||||
class CPU;
|
||||
class PPU;
|
||||
class EmulationSettings;
|
||||
class Debugger;
|
||||
|
||||
class EventManager
|
||||
{
|
||||
private:
|
||||
CPU *_cpu;
|
||||
PPU *_ppu;
|
||||
EmulationSettings *_settings;
|
||||
Debugger *_debugger;
|
||||
vector<DebugEventInfo> _debugEvents;
|
||||
vector<DebugEventInfo> _prevDebugEvents;
|
||||
vector<DebugEventInfo> _sentEvents;
|
||||
|
||||
vector<DebugEventInfo> _snapshot;
|
||||
uint16_t _snapshotScanline;
|
||||
SimpleLock _lock;
|
||||
|
||||
uint32_t _scanlineCount = 262;
|
||||
uint16_t *_ppuBuffer;
|
||||
|
||||
void DrawEvent(DebugEventInfo &evt, bool drawBackground, uint32_t *buffer, EventViewerDisplayOptions &options);
|
||||
void DrawNtscBorders(uint32_t *buffer);
|
||||
void DrawPixel(uint32_t *buffer, int32_t x, uint32_t y, uint32_t color);
|
||||
|
||||
public:
|
||||
EventManager(Debugger *debugger, CPU *cpu, PPU *ppu, EmulationSettings *settings);
|
||||
~EventManager();
|
||||
|
||||
void AddSpecialEvent(DebugEventType type);
|
||||
void AddDebugEvent(DebugEventType type, uint16_t address = -1, uint8_t value = 0, int16_t breakpointId = -1, int8_t ppuLatch = -1);
|
||||
|
||||
void GetEvents(DebugEventInfo *eventArray, uint32_t &maxEventCount, bool getPreviousFrameData);
|
||||
uint32_t GetEventCount(bool getPreviousFrameData);
|
||||
void ClearFrameEvents();
|
||||
|
||||
uint32_t TakeEventSnapshot(EventViewerDisplayOptions options);
|
||||
void GetDisplayBuffer(uint32_t *buffer, EventViewerDisplayOptions options);
|
||||
|
||||
DebugEventInfo GetEvent(int16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options);
|
||||
};
|
||||
|
||||
struct EventViewerDisplayOptions
|
||||
{
|
||||
uint32_t IrqColor;
|
||||
uint32_t NmiColor;
|
||||
uint32_t DmcDmaReadColor;
|
||||
uint32_t SpriteZeroHitColor;
|
||||
uint32_t BreakpointColor;
|
||||
uint32_t MapperRegisterReadColor;
|
||||
uint32_t MapperRegisterWriteColor;
|
||||
|
||||
uint32_t PpuRegisterReadColors[8];
|
||||
uint32_t PpuRegisterWriteColors[8];
|
||||
|
||||
bool ShowMapperRegisterWrites;
|
||||
bool ShowMapperRegisterReads;
|
||||
|
||||
bool ShowPpuRegisterWrites[8];
|
||||
bool ShowPpuRegisterReads[8];
|
||||
|
||||
bool ShowNmi;
|
||||
bool ShowIrq;
|
||||
bool ShowDmcDmaReads;
|
||||
bool ShowSpriteZeroHit;
|
||||
|
||||
bool ShowMarkedBreakpoints;
|
||||
bool ShowPreviousFrameEvents;
|
||||
bool ShowNtscBorders;
|
||||
};
|
30
Core/PPU.cpp
30
Core/PPU.cpp
|
@ -197,6 +197,10 @@ void PPU::UpdateVideoRamAddr()
|
|||
if(_scanline >= 240 || !IsRenderingEnabled()) {
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr + (_flags.VerticalWrite ? 32 : 1)) & 0x7FFF;
|
||||
|
||||
if(!_renderingEnabled) {
|
||||
_console->DebugAddDebugEvent(DebugEventType::BgColorChange);
|
||||
}
|
||||
|
||||
//Trigger memory read when setting the vram address - needed by MMC3 IRQ counter
|
||||
//"Should be clocked when A12 changes to 1 via $2007 read/write"
|
||||
SetBusAddress(_state.VideoRamAddr & 0x3FFF);
|
||||
|
@ -872,6 +876,15 @@ void PPU::DrawPixel()
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t PPU::GetCurrentBgColor()
|
||||
{
|
||||
if(IsRenderingEnabled() || (_state.VideoRamAddr & 0x3F00) != 0x3F00) {
|
||||
return _paletteRAM[0];
|
||||
} else {
|
||||
return _paletteRAM[_state.VideoRamAddr & 0x1F];
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::UpdateGrayscaleAndIntensifyBits()
|
||||
{
|
||||
if(_scanline < 0 || _scanline > _nmiScanline) {
|
||||
|
@ -1121,7 +1134,7 @@ uint8_t PPU::ReadSpriteRam(uint8_t addr)
|
|||
debugger->BreakImmediately(BreakSource::BreakOnDecayedOamRead);
|
||||
}
|
||||
}
|
||||
//If this 8-byte row hasn't been read/written to in over 3000 cpu cycles (~1.7ms), return 0xFF to simulate decay
|
||||
//If this 8-byte row hasn't been read/written to in over 3000 cpu cycles (~1.7ms), return 0x10 to simulate decay
|
||||
return 0x10;
|
||||
}
|
||||
}
|
||||
|
@ -1140,6 +1153,11 @@ void PPU::DebugSendFrame()
|
|||
_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer);
|
||||
}
|
||||
|
||||
uint16_t* PPU::GetScreenBuffer(bool previousBuffer)
|
||||
{
|
||||
return previousBuffer ? ((_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0]) : _currentOutputBuffer;
|
||||
}
|
||||
|
||||
void PPU::DebugCopyOutputBuffer(uint16_t *target)
|
||||
{
|
||||
memcpy(target, _currentOutputBuffer, PPU::PixelCount * sizeof(uint16_t));
|
||||
|
@ -1237,7 +1255,6 @@ void PPU::Exec()
|
|||
SetBusAddress(_state.VideoRamAddr);
|
||||
SendFrame();
|
||||
_frameCount++;
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
}
|
||||
} else {
|
||||
//Cycle > 0
|
||||
|
@ -1276,7 +1293,10 @@ void PPU::UpdateState()
|
|||
|
||||
//Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7)
|
||||
_prevRenderingEnabled = _renderingEnabled;
|
||||
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
||||
if(_renderingEnabled != (_flags.BackgroundEnabled | _flags.SpritesEnabled)) {
|
||||
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
||||
_console->DebugAddDebugEvent(DebugEventType::BgColorChange);
|
||||
}
|
||||
if(_prevRenderingEnabled != _renderingEnabled) {
|
||||
_needStateUpdate = true;
|
||||
}
|
||||
|
@ -1319,6 +1339,10 @@ void PPU::UpdateState()
|
|||
_state.VideoRamAddr = _updateVramAddr;
|
||||
}
|
||||
|
||||
if(!_renderingEnabled) {
|
||||
_console->DebugAddDebugEvent(DebugEventType::BgColorChange);
|
||||
}
|
||||
|
||||
//The glitches updates corrupt both V and T, so set the new value of V back into T
|
||||
_state.TmpVideoRamAddr = _state.VideoRamAddr;
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
void Reset();
|
||||
|
||||
void DebugSendFrame();
|
||||
uint16_t* GetScreenBuffer(bool previousBuffer);
|
||||
void DebugCopyOutputBuffer(uint16_t *target);
|
||||
void DebugUpdateFrameBuffer(bool toGrayscale);
|
||||
void GetState(PPUDebugState &state);
|
||||
|
@ -237,6 +238,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
|||
}
|
||||
|
||||
uint32_t GetPixelBrightness(uint8_t x, uint8_t y);
|
||||
uint8_t GetCurrentBgColor();
|
||||
|
||||
uint16_t GetPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
|
|
|
@ -153,6 +153,7 @@ namespace Mesen.GUI.Config
|
|||
public bool ShowBreakpointLabels = true;
|
||||
|
||||
public Point EventViewerLocation;
|
||||
public Size EventViewerSize;
|
||||
public bool EventViewerRefreshOnBreak = true;
|
||||
public bool EventViewerShowPpuWrite2000 = true;
|
||||
public bool EventViewerShowPpuWrite2001 = true;
|
||||
|
@ -172,6 +173,7 @@ namespace Mesen.GUI.Config
|
|||
public bool EventViewerShowMarkedBreakpoints = true;
|
||||
public bool EventViewerShowDmcDmaReads = true;
|
||||
public bool EventViewerShowPreviousFrameEvents = true;
|
||||
public bool EventViewerShowNtscBorders = true;
|
||||
|
||||
public XmlColor EventViewerMapperRegisterWriteColor = ColorTranslator.FromHtml("#007597");
|
||||
public XmlColor EventViewerMapperRegisterReadColor = ColorTranslator.FromHtml("#C92929");
|
||||
|
|
|
@ -54,6 +54,11 @@ namespace Mesen.GUI.Config
|
|||
[ShortcutName("Go to All")]
|
||||
public XmlKeys GoToAll = Keys.Control | Keys.Oemcomma;
|
||||
|
||||
[ShortcutName("Zoom In")]
|
||||
public XmlKeys ZoomIn = Keys.Control | Keys.Oemplus;
|
||||
[ShortcutName("Zoom Out")]
|
||||
public XmlKeys ZoomOut = Keys.Control | Keys.OemMinus;
|
||||
|
||||
[ShortcutName("PPU Viewer: Toggle View")]
|
||||
public XmlKeys PpuViewer_ToggleView = Keys.Control | Keys.Q;
|
||||
[ShortcutName("PPU Viewer: Toggle Zoom")]
|
||||
|
|
55
GUI.NET/Controls/ctrlPanel.cs
Normal file
55
GUI.NET/Controls/ctrlPanel.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Mesen.GUI.Controls
|
||||
{
|
||||
public class ctrlPanel : Panel
|
||||
{
|
||||
public delegate void ZoomEventHandler(int scaleDelta);
|
||||
public event ZoomEventHandler OnZoom;
|
||||
|
||||
public ctrlPanel()
|
||||
{
|
||||
this.DoubleBuffered = true;
|
||||
}
|
||||
|
||||
protected override Point ScrollToControl(Control activeControl)
|
||||
{
|
||||
// Returning the current location prevents the panel from
|
||||
// scrolling to the active control when the panel loses and regains focus
|
||||
return this.DisplayRectangle.Location;
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
if(Control.ModifierKeys != Keys.Control) {
|
||||
int hori = this.HorizontalScroll.Value;
|
||||
int vert = this.VerticalScroll.Value;
|
||||
|
||||
if(Control.ModifierKeys == Keys.Shift) {
|
||||
hori = Math.Max(0, Math.Min(hori - e.Delta, this.HorizontalScroll.Maximum));
|
||||
} else {
|
||||
vert = Math.Max(0, Math.Min(vert - e.Delta, this.VerticalScroll.Maximum));
|
||||
}
|
||||
|
||||
this.HorizontalScroll.Value = hori;
|
||||
this.HorizontalScroll.Value = hori;
|
||||
this.VerticalScroll.Value = vert;
|
||||
this.VerticalScroll.Value = vert;
|
||||
} else {
|
||||
if(Program.IsMono) {
|
||||
//Patch for Mono to prevent a scrolling bug when zooming out.
|
||||
//Breaks the zoom in/out logic to keep the current scroll position when zooming, but that's better than the original bug.
|
||||
this.HorizontalScroll.Value = 0;
|
||||
this.VerticalScroll.Value = 0;
|
||||
}
|
||||
this.OnZoom?.Invoke(e.Delta > 0 ? 1 : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,10 +37,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
public void GetData()
|
||||
{
|
||||
DebugEventInfo[] eventInfoArray;
|
||||
byte[] pictureData;
|
||||
_breakpoints = BreakpointManager.Breakpoints;
|
||||
InteropEmu.DebugGetDebugEvents(false, out pictureData, out eventInfoArray);
|
||||
DebugEventInfo[] eventInfoArray = InteropEmu.GetDebugEvents(false);
|
||||
|
||||
this.BeginInvoke((Action)(() => {
|
||||
lstEvents.BeginUpdate();
|
||||
|
|
|
@ -30,25 +30,30 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.picPicture = new Mesen.GUI.Controls.ctrlMesenPictureBox();
|
||||
this.picViewer = new Mesen.GUI.Debugger.ctrlImagePanel();
|
||||
this.tmrOverlay = new System.Windows.Forms.Timer(this.components);
|
||||
((System.ComponentModel.ISupportInitialize)(this.picPicture)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// picPicture
|
||||
//
|
||||
this.picPicture.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.picPicture.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.picPicture.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
this.picPicture.Location = new System.Drawing.Point(1, 1);
|
||||
this.picPicture.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.picPicture.Name = "picPicture";
|
||||
this.picPicture.Size = new System.Drawing.Size(684, 526);
|
||||
this.picPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.picPicture.TabIndex = 0;
|
||||
this.picPicture.TabStop = false;
|
||||
this.picPicture.MouseLeave += new System.EventHandler(this.picPicture_MouseLeave);
|
||||
this.picPicture.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picPicture_MouseMove);
|
||||
this.picViewer.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.picViewer.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.picViewer.GridSizeX = 0;
|
||||
this.picViewer.GridSizeY = 0;
|
||||
this.picViewer.Image = null;
|
||||
this.picViewer.ImageScale = 1;
|
||||
this.picViewer.ImageSize = new System.Drawing.Size(0, 0);
|
||||
this.picViewer.Location = new System.Drawing.Point(0, 0);
|
||||
this.picViewer.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.picViewer.Name = "picViewer";
|
||||
this.picViewer.Overlay = new System.Drawing.Rectangle(0, 0, 0, 0);
|
||||
this.picViewer.Selection = new System.Drawing.Rectangle(0, 0, 0, 0);
|
||||
this.picViewer.SelectionWrapPosition = 0;
|
||||
this.picViewer.Size = new System.Drawing.Size(481, 405);
|
||||
this.picViewer.TabIndex = 0;
|
||||
this.picViewer.TabStop = false;
|
||||
this.picViewer.MouseLeave += new System.EventHandler(this.picPicture_MouseLeave);
|
||||
this.picViewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.picViewer_MouseMove);
|
||||
//
|
||||
// tmrOverlay
|
||||
//
|
||||
|
@ -59,17 +64,16 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.picPicture);
|
||||
this.Controls.Add(this.picViewer);
|
||||
this.Name = "ctrlEventViewerPpuView";
|
||||
this.Size = new System.Drawing.Size(686, 530);
|
||||
((System.ComponentModel.ISupportInitialize)(this.picPicture)).EndInit();
|
||||
this.Size = new System.Drawing.Size(481, 405);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private ctrlMesenPictureBox picPicture;
|
||||
private ctrlImagePanel picViewer;
|
||||
private System.Windows.Forms.Timer tmrOverlay;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,22 +16,18 @@ using System.Drawing.Imaging;
|
|||
|
||||
namespace Mesen.GUI.Debugger.Controls
|
||||
{
|
||||
public partial class ctrlEventViewerPpuView : BaseControl, ICompactControl
|
||||
public partial class ctrlEventViewerPpuView : BaseControl
|
||||
{
|
||||
public event EventHandler OnPictureResized;
|
||||
private int _baseWidth = 341 * 2;
|
||||
private UInt32 _scanlineCount = 262;
|
||||
|
||||
private DebugState _state = new DebugState();
|
||||
private Point _lastPos = new Point(-1, -1);
|
||||
private bool _needUpdate = false;
|
||||
private Bitmap _screenBitmap = null;
|
||||
private Bitmap _eventBitmap = null;
|
||||
private Bitmap _overlayBitmap = null;
|
||||
private Bitmap _displayBitmap = null;
|
||||
private byte[] _pictureData = null;
|
||||
private Dictionary<int, List<DebugEventInfo>> _debugEventsByCycle = new Dictionary<int, List<DebugEventInfo>>();
|
||||
private List<DebugEventInfo> _debugEvents = new List<DebugEventInfo>();
|
||||
private Font _overlayFont;
|
||||
private double _scale = 1;
|
||||
|
||||
public ctrlEventViewerPpuView()
|
||||
{
|
||||
|
@ -50,49 +46,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
public void GetData()
|
||||
{
|
||||
DebugState state = new DebugState();
|
||||
InteropEmu.DebugGetState(ref state);
|
||||
|
||||
DebugEventInfo[] eventInfoArray;
|
||||
DebugEventInfo[] prevEventInfoArray = new DebugEventInfo[0];
|
||||
|
||||
InteropEmu.DebugGetDebugEvents(false, out _pictureData, out eventInfoArray);
|
||||
if(ConfigManager.Config.DebugInfo.EventViewerShowPreviousFrameEvents && (state.PPU.Scanline != -1 || state.PPU.Cycle != 0)) {
|
||||
//Get the previous frame's data, too
|
||||
InteropEmu.DebugGetDebugEvents(true, out _pictureData, out prevEventInfoArray);
|
||||
}
|
||||
|
||||
int currentCycle = (int)((state.PPU.Scanline + 1) * 341 + state.PPU.Cycle);
|
||||
var debugEvents = new Dictionary<int, List<DebugEventInfo>>();
|
||||
|
||||
List<DebugEventInfo> eventList = new List<DebugEventInfo>(eventInfoArray.Length+prevEventInfoArray.Length);
|
||||
Action<DebugEventInfo> addEvent = (DebugEventInfo eventInfo) => {
|
||||
int frameCycle = (eventInfo.Scanline + 1) * 341 + eventInfo.Cycle;
|
||||
|
||||
List<DebugEventInfo> infoList;
|
||||
if(!debugEvents.TryGetValue(frameCycle, out infoList)) {
|
||||
infoList = new List<DebugEventInfo>();
|
||||
debugEvents[frameCycle] = infoList;
|
||||
}
|
||||
infoList.Add(eventInfo);
|
||||
eventList.Add(eventInfo);
|
||||
};
|
||||
|
||||
for(int i = 0; i < eventInfoArray.Length; i++) {
|
||||
addEvent(eventInfoArray[i]);
|
||||
}
|
||||
|
||||
//Show events from the previous frame, too
|
||||
for(int i = 0; i < prevEventInfoArray.Length; i++) {
|
||||
int frameCycle = (prevEventInfoArray[i].Scanline + 1) * 341 + prevEventInfoArray[i].Cycle;
|
||||
if(frameCycle > currentCycle) {
|
||||
addEvent(prevEventInfoArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_debugEvents = eventList;
|
||||
_debugEventsByCycle = debugEvents;
|
||||
_state = state;
|
||||
EventViewerDisplayOptions options = GetInteropOptions();
|
||||
_scanlineCount = InteropEmu.TakeEventSnapshot(options);
|
||||
}
|
||||
|
||||
public static bool ShowEvent(DebugEventInfo evt)
|
||||
|
@ -136,69 +91,30 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
|
||||
public void RefreshViewer()
|
||||
{
|
||||
EventViewerDisplayOptions options = GetInteropOptions();
|
||||
_pictureData = InteropEmu.GetEventViewerOutput(_scanlineCount, options);
|
||||
|
||||
int picHeight = (int)_scanlineCount * 2;
|
||||
if(_screenBitmap == null || _screenBitmap.Height != picHeight) {
|
||||
_screenBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb);
|
||||
_overlayBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb);
|
||||
_displayBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb);
|
||||
}
|
||||
|
||||
GCHandle handle = GCHandle.Alloc(this._pictureData, GCHandleType.Pinned);
|
||||
try {
|
||||
Bitmap source = new Bitmap(256, 240, 256*4, PixelFormat.Format32bppPArgb, handle.AddrOfPinnedObject());
|
||||
int picHeight = (int)_state.PPU.ScanlineCount * 2;
|
||||
if(_eventBitmap == null || _eventBitmap.Height != picHeight) {
|
||||
_screenBitmap = new Bitmap(682, picHeight, PixelFormat.Format32bppPArgb);
|
||||
_eventBitmap = new Bitmap(682, picHeight, PixelFormat.Format32bppPArgb);
|
||||
_overlayBitmap = new Bitmap(682, picHeight, PixelFormat.Format32bppPArgb);
|
||||
_displayBitmap = new Bitmap(682, picHeight, PixelFormat.Format32bppPArgb);
|
||||
}
|
||||
|
||||
Size picSize = new Size((int)((_eventBitmap.Width * _scale) + 2), (int)((_eventBitmap.Height * _scale) + 2));
|
||||
if(picSize != this.picPicture.Size) {
|
||||
this.picPicture.Size = picSize;
|
||||
this.OnPictureResized?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
var d = ConfigManager.Config.DebugInfo;
|
||||
|
||||
List<List<Color>> colors = new List<List<Color>> {
|
||||
null, //None
|
||||
new List<Color> { d.EventViewerPpuRegisterWrite2000Color, d.EventViewerPpuRegisterWrite2001Color, Color.Black, d.EventViewerPpuRegisterWrite2003Color, d.EventViewerPpuRegisterWrite2004Color, d.EventViewerPpuRegisterWrite2005Color, d.EventViewerPpuRegisterWrite2006Color, d.EventViewerPpuRegisterWrite2007Color }, //PpuRegisterWrite
|
||||
new List<Color> { Color.Black, Color.Black, d.EventViewerPpuRegisterRead2002Color, Color.Black, d.EventViewerPpuRegisterRead2004Color, Color.Black, Color.Black, d.EventViewerPpuRegisterRead2007Color }, //PpuRegisterRead
|
||||
new List<Color> { d.EventViewerMapperRegisterWriteColor }, //MapperRegisterWrite
|
||||
new List<Color> { d.EventViewerMapperRegisterReadColor }, //MapperRegisterRead
|
||||
new List<Color> { d.EventViewerNmiColor }, //Nmi
|
||||
new List<Color> { d.EventViewerIrqColor }, //Irq
|
||||
new List<Color> { d.EventViewerSpriteZeroHitColor }, //SpriteZeroHit
|
||||
new List<Color> { d.EventViewerBreakpointColor }, //Breakpoint
|
||||
new List<Color> { d.EventViewerDmcDmaReadColor }, //DMC DMA
|
||||
};
|
||||
|
||||
Bitmap source = new Bitmap(_baseWidth, (int)_scanlineCount * 2, _baseWidth * 4, PixelFormat.Format32bppPArgb, handle.AddrOfPinnedObject());
|
||||
using(Graphics g = Graphics.FromImage(_screenBitmap)) {
|
||||
g.Clear(Color.Gray);
|
||||
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
||||
g.ScaleTransform(2, 2);
|
||||
g.DrawImageUnscaled(source, 1, 1);
|
||||
|
||||
g.ResetTransform();
|
||||
|
||||
int nmiStart = (int)(_state.PPU.NmiScanline + 1) * 2 + 1;
|
||||
int nmiEnd = (int)(_state.PPU.SafeOamScanline + 1) * 2 + 2;
|
||||
g.FillRectangle(Brushes.DimGray, 0, nmiStart, 682, nmiEnd - nmiStart);
|
||||
|
||||
g.DrawLine(Pens.Blue, 0, nmiStart, 682, nmiStart);
|
||||
g.DrawLine(Pens.Red, 0, nmiEnd, 682, nmiEnd);
|
||||
|
||||
if(_state.PPU.Scanline > 0) {
|
||||
int currentScanline = (_state.PPU.Scanline + 1) * 2 + 1;
|
||||
g.FillRectangle(Brushes.Yellow, 0, currentScanline, 682, 2);
|
||||
}
|
||||
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
|
||||
g.DrawImageUnscaled(source, 0, 0);
|
||||
}
|
||||
|
||||
using(Graphics g = Graphics.FromImage(_eventBitmap)) {
|
||||
g.Clear(Color.Transparent);
|
||||
DrawEvents(g, colors);
|
||||
}
|
||||
UpdateDisplay(true);
|
||||
} finally {
|
||||
handle.Free();
|
||||
}
|
||||
|
||||
UpdateDisplay(true);
|
||||
}
|
||||
|
||||
private void UpdateDisplay(bool forceUpdate)
|
||||
|
@ -210,53 +126,56 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
using(Graphics g = Graphics.FromImage(_displayBitmap)) {
|
||||
g.DrawImage(_screenBitmap, 0, 0);
|
||||
g.DrawImage(_overlayBitmap, 0, 0);
|
||||
g.DrawImage(_eventBitmap, 0, 0);
|
||||
|
||||
if(_lastPos.X >= 0) {
|
||||
string location = _lastPos.X / 2 + ", " + ((_lastPos.Y / 2) - 1);
|
||||
string location = _lastPos.X + ", " + (_lastPos.Y - 1);
|
||||
SizeF size = g.MeasureString(location, _overlayFont);
|
||||
int x = _lastPos.X + 15;
|
||||
int y = _lastPos.Y - (int)size.Height - 5;
|
||||
if(x + size.Width > _displayBitmap.Width - 5) {
|
||||
x -= (int)size.Width + 20;
|
||||
int x = _lastPos.X + 5;
|
||||
int y = _lastPos.Y - (int)size.Height / 2 - 5;
|
||||
|
||||
if(x * 2 - picViewer.ScrollOffsets.X / picViewer.ImageScale + size.Width > (picViewer.Width / picViewer.ImageScale) - 5) {
|
||||
x -= (int)size.Width / 2 + 10;
|
||||
}
|
||||
if(y < size.Height + 5) {
|
||||
if(y * 2 - picViewer.ScrollOffsets.Y / picViewer.ImageScale < size.Height + 5) {
|
||||
y = _lastPos.Y + 5;
|
||||
}
|
||||
|
||||
g.DrawOutlinedString(location, _overlayFont, Brushes.White, Brushes.Black, x, y);
|
||||
g.DrawOutlinedString(location, _overlayFont, Brushes.Black, Brushes.White, x * 2, y * 2);
|
||||
}
|
||||
}
|
||||
|
||||
picPicture.Image = _displayBitmap;
|
||||
picViewer.ImageSize = new Size(_baseWidth, (int)_scanlineCount * 2);
|
||||
picViewer.Image = _displayBitmap;
|
||||
_needUpdate = false;
|
||||
}
|
||||
|
||||
private Point GetCycleScanline(Point location)
|
||||
{
|
||||
return new Point(
|
||||
((location.X & ~0x01) / picViewer.ImageScale) / 2,
|
||||
((location.Y & ~0x01) / picViewer.ImageScale) / 2
|
||||
);
|
||||
}
|
||||
|
||||
private void UpdateOverlay(Point p)
|
||||
{
|
||||
int x = (int)(p.X / 2 * 2 / _scale);
|
||||
int y = (int)(p.Y / 2 * 2 / _scale);
|
||||
Point pos = GetCycleScanline(p);
|
||||
|
||||
if(_lastPos.X == x && _lastPos.Y == y) {
|
||||
if(_lastPos == pos) {
|
||||
//Same x,y location, no need to update
|
||||
return;
|
||||
}
|
||||
|
||||
using(Graphics g = Graphics.FromImage(_overlayBitmap)) {
|
||||
g.Clear(Color.Transparent);
|
||||
|
||||
using(Pen bg = new Pen(Color.FromArgb(128, Color.Black))) {
|
||||
g.DrawRectangle(bg, x - 1, 0, 3, _overlayBitmap.Height);
|
||||
g.DrawRectangle(bg, 0, y - 1, _overlayBitmap.Width, 3);
|
||||
}
|
||||
using(Pen fg = new Pen(Color.FromArgb(230, Color.Orange))) {
|
||||
g.DrawRectangle(fg, x, 0, 1, _overlayBitmap.Height);
|
||||
g.DrawRectangle(fg, 0, y, _overlayBitmap.Width, 1);
|
||||
using(Pen bg = new Pen(Color.FromArgb(128, Color.LightGray))) {
|
||||
g.DrawRectangle(bg, pos.X * 2 - 1, 0, 3, _overlayBitmap.Height);
|
||||
g.DrawRectangle(bg, 0, pos.Y * 2 - 1, _overlayBitmap.Width, 3);
|
||||
}
|
||||
}
|
||||
|
||||
_needUpdate = true;
|
||||
_lastPos = new Point(x, y);
|
||||
_lastPos = pos;
|
||||
}
|
||||
|
||||
private void ClearOverlay()
|
||||
|
@ -268,122 +187,133 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
_lastPos = new Point(-1, -1);
|
||||
}
|
||||
|
||||
private void DrawEvents(Graphics g, List<List<Color>> colors)
|
||||
private EventViewerDisplayOptions GetInteropOptions()
|
||||
{
|
||||
var enumValues = Enum.GetValues(typeof(DebugEventType));
|
||||
IGrouping<int, DebugEventInfo>[][] groupedEvents = new IGrouping<int, DebugEventInfo>[enumValues.Length][];
|
||||
foreach(DebugEventType eventType in Enum.GetValues(typeof(DebugEventType))) {
|
||||
List<Color> colorList = colors[(int)eventType];
|
||||
groupedEvents[(int)eventType] = _debugEvents.Where((v) => v.Type == eventType && ShowEvent(v)).GroupBy((v) => v.Address % colorList.Count).ToArray();
|
||||
}
|
||||
|
||||
DrawEvents(g, colors, false, groupedEvents);
|
||||
DrawEvents(g, colors, true, groupedEvents);
|
||||
DebugInfo cfg = ConfigManager.Config.DebugInfo;
|
||||
return new EventViewerDisplayOptions() {
|
||||
ShowPpuRegisterWrites = new byte[8] {
|
||||
(byte)(cfg.EventViewerShowPpuWrite2000 ? 1 : 0),
|
||||
(byte)(cfg.EventViewerShowPpuWrite2001 ? 1 : 0),
|
||||
0,
|
||||
(byte)(cfg.EventViewerShowPpuWrite2003 ? 1 : 0),
|
||||
(byte)(cfg.EventViewerShowPpuWrite2004 ? 1 : 0),
|
||||
(byte)(cfg.EventViewerShowPpuWrite2005 ? 1 : 0),
|
||||
(byte)(cfg.EventViewerShowPpuWrite2006 ? 1 : 0),
|
||||
(byte)(cfg.EventViewerShowPpuWrite2007 ? 1 : 0),
|
||||
},
|
||||
ShowPpuRegisterReads = new byte[8] {
|
||||
0,
|
||||
0,
|
||||
(byte)(cfg.EventViewerShowPpuRead2002 ? 1 : 0),
|
||||
0,
|
||||
(byte)(cfg.EventViewerShowPpuRead2004 ? 1 : 0),
|
||||
0,
|
||||
(byte)(cfg.EventViewerShowPpuRead2007 ? 1 : 0),
|
||||
0
|
||||
},
|
||||
ShowMapperRegisterWrites = cfg.EventViewerShowMapperRegisterWrites,
|
||||
ShowMapperRegisterReads = cfg.EventViewerShowMapperRegisterReads,
|
||||
MapperRegisterWriteColor = (uint)cfg.EventViewerMapperRegisterWriteColor.Color.ToArgb(),
|
||||
MapperRegisterReadColor = (uint)cfg.EventViewerMapperRegisterReadColor.Color.ToArgb(),
|
||||
ShowNmi = cfg.EventViewerShowNmi,
|
||||
ShowIrq = cfg.EventViewerShowIrq,
|
||||
ShowDmcDmaReads = cfg.EventViewerShowDmcDmaReads,
|
||||
ShowSpriteZeroHit = cfg.EventViewerShowSpriteZeroHit,
|
||||
ShowMarkedBreakpoints = cfg.EventViewerShowMarkedBreakpoints,
|
||||
ShowPreviousFrameEvents = cfg.EventViewerShowPreviousFrameEvents,
|
||||
ShowNtscBorders = cfg.EventViewerShowNtscBorders,
|
||||
IrqColor = (uint)cfg.EventViewerIrqColor.Color.ToArgb(),
|
||||
NmiColor = (uint)cfg.EventViewerNmiColor.Color.ToArgb(),
|
||||
DmcDmaReadColor = (uint)cfg.EventViewerDmcDmaReadColor.Color.ToArgb(),
|
||||
SpriteZeroHitColor = (uint)cfg.EventViewerSpriteZeroHitColor.Color.ToArgb(),
|
||||
BreakpointColor = (uint)cfg.EventViewerBreakpointColor.Color.ToArgb(),
|
||||
PpuRegisterWriteColor = new uint[8] {
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2000Color.Color.ToArgb(),
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2001Color.Color.ToArgb(),
|
||||
0,
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2003Color.Color.ToArgb(),
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2004Color.Color.ToArgb(),
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2005Color.Color.ToArgb(),
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2006Color.Color.ToArgb(),
|
||||
(uint)cfg.EventViewerPpuRegisterWrite2007Color.Color.ToArgb()
|
||||
},
|
||||
PpuRegisterReadColors = new uint[8] {
|
||||
0,
|
||||
0,
|
||||
(uint)cfg.EventViewerPpuRegisterRead2002Color.Color.ToArgb(),
|
||||
0,
|
||||
(uint)cfg.EventViewerPpuRegisterRead2004Color.Color.ToArgb(),
|
||||
0,
|
||||
(uint)cfg.EventViewerPpuRegisterRead2007Color.Color.ToArgb(),
|
||||
0
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static void DrawEvents(Graphics g, List<List<Color>> colors, bool drawFg, IGrouping<int, DebugEventInfo>[][] groupedEvents)
|
||||
{
|
||||
int size = drawFg ? 2 : 6;
|
||||
int offset = drawFg ? 0 : 2;
|
||||
foreach(DebugEventType eventType in Enum.GetValues(typeof(DebugEventType))) {
|
||||
if(groupedEvents[(int)eventType] != null) {
|
||||
foreach(var eventGroup in groupedEvents[(int)eventType]) {
|
||||
List<Rectangle> rects = new List<Rectangle>(eventGroup.Count());
|
||||
foreach(DebugEventInfo evt in eventGroup) {
|
||||
rects.Add(new Rectangle(evt.Cycle * 2 - offset, evt.Scanline * 2 - offset + 2, size, size));
|
||||
}
|
||||
|
||||
List<Color> colorList = colors[(int)eventType];
|
||||
Color color = colorList[eventGroup.Key];
|
||||
using(Brush b = new SolidBrush(drawFg ? color : ControlPaint.Dark(color))) {
|
||||
g.FillRectangles(b, rects.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _lastKey = -1;
|
||||
private frmCodeTooltip _tooltip = null;
|
||||
private void picPicture_MouseMove(object sender, MouseEventArgs e)
|
||||
private void picViewer_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
int cycle = e.X * 341 / (picPicture.Width - 2);
|
||||
int scanline = e.Y * (int)_state.PPU.ScanlineCount / (picPicture.Height - 2) - 1;
|
||||
|
||||
int[] offsets = new int[3] { 0, -1, 1 };
|
||||
|
||||
for(int y = 0; y < 3; y++) {
|
||||
for(int x = 0; x < 3; x++) {
|
||||
int key = (scanline + offsets[y] + 1) * 341 + cycle + offsets[x];
|
||||
|
||||
List<DebugEventInfo> eventList;
|
||||
if(_debugEventsByCycle.TryGetValue(key, out eventList)) {
|
||||
foreach(DebugEventInfo debugEvent in eventList) {
|
||||
if(ShowEvent(debugEvent)) {
|
||||
if(key != _lastKey) {
|
||||
ResetTooltip();
|
||||
|
||||
Dictionary<string, string> values = new Dictionary<string, string>() {
|
||||
{ "Type", ResourceHelper.GetEnumText(debugEvent.Type) },
|
||||
{ "Scanline", debugEvent.Scanline.ToString() },
|
||||
{ "Cycle", debugEvent.Cycle.ToString() },
|
||||
{ "PC", "$" + debugEvent.ProgramCounter.ToString("X4") },
|
||||
};
|
||||
|
||||
switch(debugEvent.Type) {
|
||||
case DebugEventType.MapperRegisterRead:
|
||||
case DebugEventType.MapperRegisterWrite:
|
||||
case DebugEventType.PpuRegisterRead:
|
||||
case DebugEventType.PpuRegisterWrite:
|
||||
values["Register"] = "$" + debugEvent.Address.ToString("X4");
|
||||
values["Value"] = "$" + debugEvent.Value.ToString("X2");
|
||||
|
||||
if(debugEvent.PpuLatch >= 0) {
|
||||
values["2nd Write"] = debugEvent.PpuLatch == 0 ? "false" : "true";
|
||||
}
|
||||
break;
|
||||
|
||||
case DebugEventType.DmcDmaRead:
|
||||
values["Address"] = "$" + debugEvent.Address.ToString("X4");
|
||||
values["Value"] = "$" + debugEvent.Value.ToString("X2");
|
||||
break;
|
||||
|
||||
case DebugEventType.Breakpoint:
|
||||
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
|
||||
if(debugEvent.BreakpointId >= 0 && debugEvent.BreakpointId < breakpoints.Count) {
|
||||
Breakpoint bp = breakpoints[debugEvent.BreakpointId];
|
||||
values["BP Type"] = bp.ToReadableType();
|
||||
values["BP Addresses"] = bp.GetAddressString(true);
|
||||
if(bp.Condition.Length > 0) {
|
||||
values["BP Condition"] = bp.Condition;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateOverlay(new Point((int)(debugEvent.Cycle * 2 * _scale), (int)((debugEvent.Scanline + 1) * 2 * _scale)));
|
||||
|
||||
Form parentForm = this.FindForm();
|
||||
_tooltip = new frmCodeTooltip(parentForm, values, null, null, null, 10);
|
||||
_tooltip.FormClosed += (s, evt) => { _tooltip = null; };
|
||||
Point location = PointToScreen(e.Location);
|
||||
location.Offset(10, 10);
|
||||
_tooltip.SetFormLocation(location, this);
|
||||
_lastKey = key;
|
||||
}
|
||||
|
||||
//Found a matching write to display, stop processing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Point pos = GetCycleScanline(e.Location);
|
||||
if(_lastPos == pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateOverlay(e.Location);
|
||||
EventViewerDisplayOptions options = GetInteropOptions();
|
||||
DebugEventInfo debugEvent = new DebugEventInfo();
|
||||
InteropEmu.GetEventViewerEvent(ref debugEvent, (Int16)(pos.Y - 1), (UInt16)pos.X, options);
|
||||
if(debugEvent.ProgramCounter == 0xFFFFFFFF) {
|
||||
ResetTooltip();
|
||||
UpdateOverlay(e.Location);
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, string> values = new Dictionary<string, string>() {
|
||||
{ "Type", ResourceHelper.GetEnumText(debugEvent.Type) },
|
||||
{ "Scanline", debugEvent.Scanline.ToString() },
|
||||
{ "Cycle", debugEvent.Cycle.ToString() },
|
||||
{ "PC", "$" + debugEvent.ProgramCounter.ToString("X4") },
|
||||
};
|
||||
|
||||
switch(debugEvent.Type) {
|
||||
case DebugEventType.MapperRegisterRead:
|
||||
case DebugEventType.MapperRegisterWrite:
|
||||
case DebugEventType.PpuRegisterRead:
|
||||
case DebugEventType.PpuRegisterWrite:
|
||||
values["Register"] = "$" + debugEvent.Address.ToString("X4");
|
||||
values["Value"] = "$" + debugEvent.Value.ToString("X2");
|
||||
|
||||
if(debugEvent.PpuLatch >= 0) {
|
||||
values["2nd Write"] = debugEvent.PpuLatch == 0 ? "false" : "true";
|
||||
}
|
||||
break;
|
||||
|
||||
case DebugEventType.DmcDmaRead:
|
||||
values["Address"] = "$" + debugEvent.Address.ToString("X4");
|
||||
values["Value"] = "$" + debugEvent.Value.ToString("X2");
|
||||
break;
|
||||
|
||||
case DebugEventType.Breakpoint:
|
||||
ReadOnlyCollection<Breakpoint> breakpoints = BreakpointManager.Breakpoints;
|
||||
if(debugEvent.BreakpointId >= 0 && debugEvent.BreakpointId < breakpoints.Count) {
|
||||
Breakpoint bp = breakpoints[debugEvent.BreakpointId];
|
||||
values["BP Type"] = bp.ToReadableType();
|
||||
values["BP Addresses"] = bp.GetAddressString(true);
|
||||
if(bp.Condition.Length > 0) {
|
||||
values["BP Condition"] = bp.Condition;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//No match found, make sure any existing tooltip is closed
|
||||
ResetTooltip();
|
||||
UpdateOverlay(new Point((int)(debugEvent.Cycle * 2 * picViewer.ImageScale), (int)((debugEvent.Scanline + 1) * 2 * picViewer.ImageScale)));
|
||||
|
||||
Form parentForm = this.FindForm();
|
||||
_tooltip = new frmCodeTooltip(parentForm, values, null, null, null, 10);
|
||||
_tooltip.FormClosed += (s, evt) => { _tooltip = null; };
|
||||
Point location = this.PointToScreen(new Point(e.Location.X - picViewer.ScrollOffsets.X, e.Location.Y - picViewer.ScrollOffsets.Y));
|
||||
location.Offset(10, 10);
|
||||
_tooltip.SetFormLocation(location, this);
|
||||
}
|
||||
|
||||
private void ResetTooltip()
|
||||
|
@ -392,7 +322,6 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
_tooltip.Close();
|
||||
_tooltip = null;
|
||||
}
|
||||
_lastKey = -1;
|
||||
}
|
||||
|
||||
private void picPicture_MouseLeave(object sender, EventArgs e)
|
||||
|
@ -406,15 +335,14 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
UpdateDisplay(false);
|
||||
}
|
||||
|
||||
public Size GetCompactSize(bool includeMargins)
|
||||
public void ZoomIn()
|
||||
{
|
||||
return picPicture.Size + picPicture.Margin.Size;
|
||||
picViewer.ZoomIn();
|
||||
}
|
||||
|
||||
public void ScaleImage(double scale)
|
||||
public void ZoomOut()
|
||||
{
|
||||
_scale *= scale;
|
||||
picPicture.Size = new Size((int)(picPicture.Width * scale), (int)(picPicture.Height * scale));
|
||||
picViewer.ZoomOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
73
GUI.NET/Debugger/Controls/ctrlImagePanel.Designer.cs
generated
Normal file
73
GUI.NET/Debugger/Controls/ctrlImagePanel.Designer.cs
generated
Normal file
|
@ -0,0 +1,73 @@
|
|||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
partial class ctrlImagePanel
|
||||
{
|
||||
/// <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.ctrlPanel = new Mesen.GUI.Controls.ctrlPanel();
|
||||
this.ctrlImageViewer = new Mesen.GUI.Debugger.ctrlImageViewer();
|
||||
this.ctrlPanel.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// ctrlPanel
|
||||
//
|
||||
this.ctrlPanel.AutoScroll = true;
|
||||
this.ctrlPanel.Controls.Add(this.ctrlImageViewer);
|
||||
this.ctrlPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlPanel.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlPanel.Name = "ctrlPanel";
|
||||
this.ctrlPanel.Size = new System.Drawing.Size(327, 326);
|
||||
this.ctrlPanel.TabIndex = 0;
|
||||
//
|
||||
// ctrlImageViewer
|
||||
//
|
||||
this.ctrlImageViewer.Image = null;
|
||||
this.ctrlImageViewer.ImageScale = 1;
|
||||
this.ctrlImageViewer.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlImageViewer.Name = "ctrlImageViewer";
|
||||
this.ctrlImageViewer.Selection = new System.Drawing.Rectangle(0, 0, 0, 0);
|
||||
this.ctrlImageViewer.Size = new System.Drawing.Size(327, 326);
|
||||
this.ctrlImageViewer.TabIndex = 0;
|
||||
this.ctrlImageViewer.Text = "ctrlImageViewer";
|
||||
//
|
||||
// ctrlImagePanel
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.ctrlPanel);
|
||||
this.Name = "ctrlImagePanel";
|
||||
this.Size = new System.Drawing.Size(327, 326);
|
||||
this.ctrlPanel.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Mesen.GUI.Controls.ctrlPanel ctrlPanel;
|
||||
private ctrlImageViewer ctrlImageViewer;
|
||||
}
|
||||
}
|
147
GUI.NET/Debugger/Controls/ctrlImagePanel.cs
Normal file
147
GUI.NET/Debugger/Controls/ctrlImagePanel.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
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.Controls;
|
||||
using Mesen.GUI.Forms;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public partial class ctrlImagePanel : BaseControl
|
||||
{
|
||||
private int _scale = 1;
|
||||
private Size _imageSize;
|
||||
|
||||
private bool _mouseDown = false;
|
||||
private Point _lastLocation = Point.Empty;
|
||||
|
||||
public Rectangle Selection { get { return ctrlImageViewer.Selection; } set { ctrlImageViewer.Selection = value; } }
|
||||
public Rectangle Overlay { get { return ctrlImageViewer.Overlay; } set { ctrlImageViewer.Overlay = value; } }
|
||||
public int SelectionWrapPosition { get { return ctrlImageViewer.SelectionWrapPosition; } set { ctrlImageViewer.SelectionWrapPosition = value; } }
|
||||
|
||||
public Size ImageSize { get { return _imageSize; } set { _imageSize = value; UpdateMapSize(); } }
|
||||
public Image Image { get { return ctrlImageViewer.Image; } set { ctrlImageViewer.Image = value; } }
|
||||
public int ImageScale { get { return _scale; } set { _scale = value; UpdateMapSize(); } }
|
||||
public int GridSizeX { get { return ctrlImageViewer.GridSizeX; } set { ctrlImageViewer.GridSizeX = value; } }
|
||||
public int GridSizeY { get { return ctrlImageViewer.GridSizeY; } set { ctrlImageViewer.GridSizeY = value; } }
|
||||
public Point ScrollOffsets { get { return new Point(ctrlPanel.HorizontalScroll.Value, ctrlPanel.VerticalScroll.Value); } }
|
||||
|
||||
public new event EventHandler MouseLeave { add { ctrlImageViewer.MouseLeave += value; } remove { ctrlImageViewer.MouseLeave -= value; } }
|
||||
public new event MouseEventHandler MouseMove { add { ctrlImageViewer.MouseMove += value; } remove { ctrlImageViewer.MouseMove -= value; } }
|
||||
public new event MouseEventHandler MouseClick;
|
||||
|
||||
public ctrlImagePanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if(DesignMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctrlPanel.OnZoom += (scaleDelta) => {
|
||||
double hori = (double)ctrlPanel.HorizontalScroll.Value / _scale + (double)ctrlPanel.Width / 2 / _scale;
|
||||
double vert = (double)ctrlPanel.VerticalScroll.Value / _scale + (double)ctrlPanel.Height / 2 / _scale;
|
||||
|
||||
_scale = Math.Min(16, Math.Max(1, _scale + scaleDelta));
|
||||
UpdateMapSize();
|
||||
|
||||
int horizontalScroll = Math.Max(0, Math.Min((int)(hori * _scale) - ctrlPanel.Width / 2, ctrlPanel.HorizontalScroll.Maximum));
|
||||
int verticalScroll = Math.Max(0, Math.Min((int)(vert * _scale) - ctrlPanel.Height / 2, ctrlPanel.VerticalScroll.Maximum));
|
||||
|
||||
//Set the values twice to avoid a scroll position bug
|
||||
ctrlPanel.HorizontalScroll.Value = horizontalScroll;
|
||||
ctrlPanel.HorizontalScroll.Value = horizontalScroll;
|
||||
ctrlPanel.VerticalScroll.Value = verticalScroll;
|
||||
ctrlPanel.VerticalScroll.Value = verticalScroll;
|
||||
};
|
||||
|
||||
ctrlImageViewer.MouseDown += (s, e) => {
|
||||
if(e.Button == MouseButtons.Left) {
|
||||
_mouseDown = true;
|
||||
_lastLocation = e.Location;
|
||||
}
|
||||
};
|
||||
|
||||
ctrlImageViewer.MouseUp += (s, e) => {
|
||||
_mouseDown = false;
|
||||
};
|
||||
|
||||
ctrlImageViewer.MouseClick += (s, e) => {
|
||||
this.MouseClick?.Invoke(s, e);
|
||||
};
|
||||
|
||||
ctrlImageViewer.MouseMove += ctrlImageViewer_MouseMove;
|
||||
}
|
||||
|
||||
private void ctrlImageViewer_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if(_mouseDown) {
|
||||
ctrlImageViewer.MouseMove -= ctrlImageViewer_MouseMove;
|
||||
int hScroll = Math.Min(ctrlPanel.HorizontalScroll.Maximum, Math.Max(0, ctrlPanel.HorizontalScroll.Value - (e.Location.X - _lastLocation.X)));
|
||||
int vScroll = Math.Min(ctrlPanel.VerticalScroll.Maximum, Math.Max(0, ctrlPanel.VerticalScroll.Value - (e.Location.Y - _lastLocation.Y)));
|
||||
|
||||
ctrlPanel.HorizontalScroll.Value = hScroll;
|
||||
ctrlPanel.HorizontalScroll.Value = hScroll;
|
||||
ctrlPanel.VerticalScroll.Value = vScroll;
|
||||
ctrlPanel.VerticalScroll.Value = vScroll;
|
||||
ctrlImageViewer.MouseMove += ctrlImageViewer_MouseMove;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMapSize()
|
||||
{
|
||||
ctrlImageViewer.Width = ImageSize.Width * _scale;
|
||||
ctrlImageViewer.Height = ImageSize.Height * _scale;
|
||||
ctrlImageViewer.ImageScale = _scale;
|
||||
ctrlImageViewer.Invalidate();
|
||||
}
|
||||
|
||||
protected override void OnInvalidated(InvalidateEventArgs e)
|
||||
{
|
||||
base.OnInvalidated(e);
|
||||
ctrlImageViewer.Invalidate();
|
||||
}
|
||||
|
||||
public void ZoomIn()
|
||||
{
|
||||
_scale = Math.Min(16, _scale + 1);
|
||||
UpdateMapSize();
|
||||
}
|
||||
|
||||
public void ZoomOut()
|
||||
{
|
||||
_scale = Math.Max(1, _scale - 1);
|
||||
UpdateMapSize();
|
||||
}
|
||||
|
||||
public void ScrollTo(int scrollPos)
|
||||
{
|
||||
ctrlPanel.VerticalScroll.Value = scrollPos;
|
||||
ctrlPanel.VerticalScroll.Value = scrollPos;
|
||||
|
||||
ctrlPanel.HorizontalScroll.Value = 0;
|
||||
ctrlPanel.HorizontalScroll.Value = 0;
|
||||
}
|
||||
|
||||
public void CopyToClipboard()
|
||||
{
|
||||
Clipboard.SetImage(this.Image);
|
||||
}
|
||||
|
||||
public void SaveAsPng()
|
||||
{
|
||||
using(SaveFileDialog sfd = new SaveFileDialog()) {
|
||||
sfd.SetFilter("PNG files|*.png");
|
||||
if(sfd.ShowDialog() == DialogResult.OK) {
|
||||
this.Image.Save(sfd.FileName, ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
GUI.NET/Debugger/Controls/ctrlImagePanel.resx
Normal file
120
GUI.NET/Debugger/Controls/ctrlImagePanel.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>
|
128
GUI.NET/Debugger/Controls/ctrlImageViewer.cs
Normal file
128
GUI.NET/Debugger/Controls/ctrlImageViewer.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Mesen.GUI.Debugger
|
||||
{
|
||||
public class ctrlImageViewer : Control
|
||||
{
|
||||
private Image _image = null;
|
||||
private Rectangle _selection = Rectangle.Empty;
|
||||
private Rectangle _overlay = Rectangle.Empty;
|
||||
private int _selectionWrapPosition = 0;
|
||||
private int _gridSizeX = 0;
|
||||
private int _gridSizeY = 0;
|
||||
|
||||
public ctrlImageViewer()
|
||||
{
|
||||
this.DoubleBuffered = true;
|
||||
this.ResizeRedraw = true;
|
||||
}
|
||||
|
||||
public Image Image
|
||||
{
|
||||
get { return _image; }
|
||||
set { _image = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public Rectangle Selection
|
||||
{
|
||||
get { return _selection; }
|
||||
set { _selection = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public Rectangle Overlay
|
||||
{
|
||||
get { return _overlay; }
|
||||
set { _overlay = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public int GridSizeX
|
||||
{
|
||||
get { return _gridSizeX; }
|
||||
set { _gridSizeX = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public int GridSizeY
|
||||
{
|
||||
get { return _gridSizeY; }
|
||||
set { _gridSizeY = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public int SelectionWrapPosition
|
||||
{
|
||||
get { return _selectionWrapPosition; }
|
||||
set { _selectionWrapPosition = value; this.Invalidate(); }
|
||||
}
|
||||
|
||||
public int ImageScale { get; set; } = 1;
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
|
||||
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
|
||||
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
|
||||
e.Graphics.ScaleTransform(this.ImageScale, this.ImageScale);
|
||||
|
||||
if(this.Image != null) {
|
||||
e.Graphics.DrawImage(this.Image, 0, 0);
|
||||
}
|
||||
e.Graphics.ResetTransform();
|
||||
|
||||
using(Pen gridPen = new Pen(Color.FromArgb(180, Color.LightBlue))) {
|
||||
if(_gridSizeX > 1) {
|
||||
for(int i = this.ImageScale * _gridSizeX; i < this.Width; i += this.ImageScale * _gridSizeX) {
|
||||
e.Graphics.DrawLine(gridPen, i, 0, i, this.Height);
|
||||
}
|
||||
}
|
||||
if(_gridSizeY > 1) {
|
||||
for(int i = this.ImageScale * _gridSizeY; i < this.Height; i += this.ImageScale * _gridSizeY) {
|
||||
e.Graphics.DrawLine(gridPen, 0, i, this.Width, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_overlay != Rectangle.Empty) {
|
||||
using(SolidBrush brush = new SolidBrush(Color.FromArgb(100, 240, 240, 240))) {
|
||||
int scale = this.ImageScale;
|
||||
Rectangle rect = new Rectangle(_overlay.Left * scale % this.Width, _overlay.Top * scale % this.Height, _overlay.Width * scale, _overlay.Height * scale);
|
||||
|
||||
e.Graphics.FillRectangle(brush, rect.Left, rect.Top, rect.Width, rect.Height);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, rect.Left, rect.Top, rect.Width, rect.Height);
|
||||
|
||||
if((rect.Top + rect.Height) > this.Height) {
|
||||
e.Graphics.FillRectangle(brush, rect.Left, rect.Top - this.Height, rect.Width, rect.Height);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, rect.Left, rect.Top - this.Height, rect.Width, rect.Height);
|
||||
}
|
||||
|
||||
if((rect.Left + rect.Width) > this.Width) {
|
||||
e.Graphics.FillRectangle(brush, rect.Left - this.Width, rect.Top, rect.Width, rect.Height);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, rect.Left - this.Width, rect.Top, rect.Width, rect.Height);
|
||||
|
||||
if((rect.Top + rect.Height) > this.Height) {
|
||||
e.Graphics.FillRectangle(brush, rect.Left - this.Width, rect.Top - this.Height, rect.Width, rect.Height);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, rect.Left - this.Width, rect.Top - this.Height, rect.Width, rect.Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_selection != Rectangle.Empty) {
|
||||
int scale = this.ImageScale;
|
||||
e.Graphics.DrawRectangle(Pens.White, _selection.Left * scale, _selection.Top * scale, _selection.Width * scale + 0.5f, _selection.Height * scale + 0.5f);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, _selection.Left * scale - 1, _selection.Top * scale - 1, _selection.Width * scale + 2.5f, _selection.Height * scale + 2.5f);
|
||||
|
||||
if(_selectionWrapPosition > 0 && _selection.Top + _selection.Height > _selectionWrapPosition) {
|
||||
e.Graphics.DrawRectangle(Pens.White, _selection.Left * scale, _selection.Top * scale - _selectionWrapPosition * scale, _selection.Width * scale + 0.5f, _selection.Height * scale + 0.5f);
|
||||
e.Graphics.DrawRectangle(Pens.Gray, _selection.Left * scale - 1, _selection.Top * scale - 1 - _selectionWrapPosition * scale, _selection.Width * scale + 2.5f, _selection.Height * scale + 2.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ namespace Mesen.GUI.Debugger
|
|||
GetMember(nameof(DebuggerShortcutsConfig.IncreaseFontSize)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.DecreaseFontSize)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.ResetFontSize)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.ZoomIn)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.ZoomOut)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.GoTo)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.Find)),
|
||||
GetMember(nameof(DebuggerShortcutsConfig.FindNext)),
|
||||
|
|
91
GUI.NET/Debugger/frmEventViewer.Designer.cs
generated
91
GUI.NET/Debugger/frmEventViewer.Designer.cs
generated
|
@ -33,8 +33,10 @@
|
|||
{
|
||||
this.tabMain = new System.Windows.Forms.TabControl();
|
||||
this.tpgPpuView = new System.Windows.Forms.TabPage();
|
||||
this.ctrlEventViewerPpuView = new Mesen.GUI.Debugger.Controls.ctrlEventViewerPpuView();
|
||||
this.grpShow = new System.Windows.Forms.GroupBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkShowNtscBorders = new System.Windows.Forms.CheckBox();
|
||||
this.lblPpuWrites = new System.Windows.Forms.Label();
|
||||
this.chkShowMapperRegisterWrites = new System.Windows.Forms.CheckBox();
|
||||
this.chkShowPreviousFrameEvents = new System.Windows.Forms.CheckBox();
|
||||
|
@ -73,7 +75,6 @@
|
|||
this.picSpriteZeroHit = new Mesen.GUI.Debugger.ctrlColorPicker();
|
||||
this.picBreakpoint = new Mesen.GUI.Debugger.ctrlColorPicker();
|
||||
this.picDmcDmaRead = new Mesen.GUI.Debugger.ctrlColorPicker();
|
||||
this.ctrlEventViewerPpuView = new Mesen.GUI.Debugger.Controls.ctrlEventViewerPpuView();
|
||||
this.tpgListView = new System.Windows.Forms.TabPage();
|
||||
this.ctrlEventViewerListView = new Mesen.GUI.Debugger.Controls.ctrlEventViewerListView();
|
||||
this.menuStrip1 = new Mesen.GUI.Controls.ctrlMesenMenuStrip();
|
||||
|
@ -83,8 +84,9 @@
|
|||
this.mnuRefreshOnBreak = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuResetColors = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.chkToggleZoom = new System.Windows.Forms.CheckBox();
|
||||
this.btnToggleView = new System.Windows.Forms.Button();
|
||||
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuZoomIn = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuZoomOut = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.tabMain.SuspendLayout();
|
||||
this.tpgPpuView.SuspendLayout();
|
||||
this.grpShow.SuspendLayout();
|
||||
|
@ -124,8 +126,8 @@
|
|||
//
|
||||
// tpgPpuView
|
||||
//
|
||||
this.tpgPpuView.Controls.Add(this.grpShow);
|
||||
this.tpgPpuView.Controls.Add(this.ctrlEventViewerPpuView);
|
||||
this.tpgPpuView.Controls.Add(this.grpShow);
|
||||
this.tpgPpuView.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgPpuView.Name = "tpgPpuView";
|
||||
this.tpgPpuView.Padding = new System.Windows.Forms.Padding(3);
|
||||
|
@ -134,6 +136,14 @@
|
|||
this.tpgPpuView.Text = "PPU View";
|
||||
this.tpgPpuView.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ctrlEventViewerPpuView
|
||||
//
|
||||
this.ctrlEventViewerPpuView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ctrlEventViewerPpuView.Location = new System.Drawing.Point(3, 3);
|
||||
this.ctrlEventViewerPpuView.Name = "ctrlEventViewerPpuView";
|
||||
this.ctrlEventViewerPpuView.Size = new System.Drawing.Size(686, 532);
|
||||
this.ctrlEventViewerPpuView.TabIndex = 0;
|
||||
//
|
||||
// grpShow
|
||||
//
|
||||
this.grpShow.Controls.Add(this.tableLayoutPanel2);
|
||||
|
@ -152,6 +162,7 @@
|
|||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 31F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 25F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkShowNtscBorders, 0, 20);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblPpuWrites, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkShowMapperRegisterWrites, 0, 9);
|
||||
this.tableLayoutPanel2.Controls.Add(this.chkShowPreviousFrameEvents, 0, 19);
|
||||
|
@ -194,7 +205,7 @@
|
|||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 20;
|
||||
this.tableLayoutPanel2.RowCount = 21;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
|
@ -214,10 +225,23 @@
|
|||
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());
|
||||
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(180, 513);
|
||||
this.tableLayoutPanel2.TabIndex = 2;
|
||||
//
|
||||
// chkShowNtscBorders
|
||||
//
|
||||
this.chkShowNtscBorders.AutoSize = true;
|
||||
this.tableLayoutPanel2.SetColumnSpan(this.chkShowNtscBorders, 4);
|
||||
this.chkShowNtscBorders.Location = new System.Drawing.Point(3, 405);
|
||||
this.chkShowNtscBorders.Name = "chkShowNtscBorders";
|
||||
this.chkShowNtscBorders.Size = new System.Drawing.Size(123, 17);
|
||||
this.chkShowNtscBorders.TabIndex = 67;
|
||||
this.chkShowNtscBorders.Text = "Show NTSC borders";
|
||||
this.chkShowNtscBorders.UseVisualStyleBackColor = true;
|
||||
this.chkShowNtscBorders.Click += new System.EventHandler(this.chkShowHide_Click);
|
||||
//
|
||||
// lblPpuWrites
|
||||
//
|
||||
this.lblPpuWrites.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
|
@ -657,15 +681,6 @@
|
|||
this.picDmcDmaRead.TabStop = false;
|
||||
this.picDmcDmaRead.BackColorChanged += new System.EventHandler(this.picColor_BackColorChanged);
|
||||
//
|
||||
// ctrlEventViewerPpuView
|
||||
//
|
||||
this.ctrlEventViewerPpuView.Location = new System.Drawing.Point(0, 0);
|
||||
this.ctrlEventViewerPpuView.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.ctrlEventViewerPpuView.Name = "ctrlEventViewerPpuView";
|
||||
this.ctrlEventViewerPpuView.Size = new System.Drawing.Size(685, 532);
|
||||
this.ctrlEventViewerPpuView.TabIndex = 0;
|
||||
this.ctrlEventViewerPpuView.OnPictureResized += new System.EventHandler(this.ctrlEventViewerPpuView_OnPictureResized);
|
||||
//
|
||||
// tpgListView
|
||||
//
|
||||
this.tpgListView.Controls.Add(this.ctrlEventViewerListView);
|
||||
|
@ -717,7 +732,10 @@
|
|||
this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuRefreshOnBreak,
|
||||
this.toolStripMenuItem1,
|
||||
this.mnuResetColors});
|
||||
this.mnuResetColors,
|
||||
this.toolStripMenuItem2,
|
||||
this.mnuZoomIn,
|
||||
this.mnuZoomOut});
|
||||
this.viewToolStripMenuItem.Name = "viewToolStripMenuItem";
|
||||
this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
|
||||
this.viewToolStripMenuItem.Text = "View";
|
||||
|
@ -742,41 +760,30 @@
|
|||
this.mnuResetColors.Text = "Reset colors to default";
|
||||
this.mnuResetColors.Click += new System.EventHandler(this.mnuResetColors_Click);
|
||||
//
|
||||
// chkToggleZoom
|
||||
// toolStripMenuItem2
|
||||
//
|
||||
this.chkToggleZoom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.chkToggleZoom.Appearance = System.Windows.Forms.Appearance.Button;
|
||||
this.chkToggleZoom.AutoCheck = false;
|
||||
this.chkToggleZoom.Image = global::Mesen.GUI.Properties.Resources.Zoom2x;
|
||||
this.chkToggleZoom.Location = new System.Drawing.Point(824, 1);
|
||||
this.chkToggleZoom.Name = "chkToggleZoom";
|
||||
this.chkToggleZoom.Size = new System.Drawing.Size(27, 22);
|
||||
this.chkToggleZoom.TabIndex = 8;
|
||||
this.chkToggleZoom.UseVisualStyleBackColor = true;
|
||||
this.chkToggleZoom.Click += new System.EventHandler(this.chkToggleZoom_Click);
|
||||
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
|
||||
this.toolStripMenuItem2.Size = new System.Drawing.Size(195, 6);
|
||||
//
|
||||
// btnToggleView
|
||||
// mnuZoomIn
|
||||
//
|
||||
this.btnToggleView.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnToggleView.Image = global::Mesen.GUI.Properties.Resources.Collapse;
|
||||
this.btnToggleView.Location = new System.Drawing.Point(857, 1);
|
||||
this.btnToggleView.Name = "btnToggleView";
|
||||
this.btnToggleView.Size = new System.Drawing.Size(27, 22);
|
||||
this.btnToggleView.TabIndex = 7;
|
||||
this.btnToggleView.UseVisualStyleBackColor = true;
|
||||
this.btnToggleView.Click += new System.EventHandler(this.btnToggleView_Click);
|
||||
this.mnuZoomIn.Name = "mnuZoomIn";
|
||||
this.mnuZoomIn.Size = new System.Drawing.Size(198, 22);
|
||||
this.mnuZoomIn.Text = "Zoom In";
|
||||
//
|
||||
// mnuZoomOut
|
||||
//
|
||||
this.mnuZoomOut.Name = "mnuZoomOut";
|
||||
this.mnuZoomOut.Size = new System.Drawing.Size(198, 22);
|
||||
this.mnuZoomOut.Text = "Zoom Out";
|
||||
//
|
||||
// frmEventViewer
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(886, 588);
|
||||
this.Controls.Add(this.chkToggleZoom);
|
||||
this.Controls.Add(this.btnToggleView);
|
||||
this.Controls.Add(this.tabMain);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "frmEventViewer";
|
||||
this.Text = "Event Viewer";
|
||||
this.tabMain.ResumeLayout(false);
|
||||
|
@ -830,8 +837,6 @@
|
|||
private System.Windows.Forms.TabPage tpgListView;
|
||||
private Controls.ctrlEventViewerListView ctrlEventViewerListView;
|
||||
private System.Windows.Forms.CheckBox chkShowPreviousFrameEvents;
|
||||
private System.Windows.Forms.CheckBox chkToggleZoom;
|
||||
private System.Windows.Forms.Button btnToggleView;
|
||||
private System.Windows.Forms.Label lblPpuWrites;
|
||||
private System.Windows.Forms.CheckBox chkWrite2000;
|
||||
private ctrlColorPicker picWrite2000;
|
||||
|
@ -865,5 +870,9 @@
|
|||
private System.Windows.Forms.ToolStripMenuItem mnuResetColors;
|
||||
private System.Windows.Forms.CheckBox chkShowDmcDmaRead;
|
||||
private ctrlColorPicker picDmcDmaRead;
|
||||
private System.Windows.Forms.CheckBox chkShowNtscBorders;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuZoomIn;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuZoomOut;
|
||||
}
|
||||
}
|
|
@ -19,10 +19,6 @@ namespace Mesen.GUI.Debugger
|
|||
private EntityBinder _binder = new EntityBinder();
|
||||
private bool _inListViewTab = false;
|
||||
private bool _refreshing = false;
|
||||
private bool _isZoomed = false;
|
||||
private bool _isCompact = false;
|
||||
private Size _originalSize;
|
||||
private Size _previousPictureSize;
|
||||
|
||||
public frmEventViewer()
|
||||
{
|
||||
|
@ -79,20 +75,7 @@ namespace Mesen.GUI.Debugger
|
|||
_binder.AddBinding(nameof(DebugInfo.EventViewerDmcDmaReadColor), picDmcDmaRead);
|
||||
|
||||
_binder.AddBinding(nameof(DebugInfo.EventViewerShowPreviousFrameEvents), chkShowPreviousFrameEvents);
|
||||
|
||||
string toggleViewTooltip = "Toggle Compact/Normal View";
|
||||
if(ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleView != Keys.None) {
|
||||
toggleViewTooltip += " (" + DebuggerShortcutsConfig.GetShortcutDisplay(ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleView) + ")";
|
||||
}
|
||||
this.toolTip.SetToolTip(this.btnToggleView, toggleViewTooltip);
|
||||
|
||||
string toggleZoomTooltip = "Toggle 2x Zoom";
|
||||
if(ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleZoom != Keys.None) {
|
||||
toggleZoomTooltip += " (" + DebuggerShortcutsConfig.GetShortcutDisplay(ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleZoom) + ")";
|
||||
}
|
||||
this.toolTip.SetToolTip(this.chkToggleZoom, toggleZoomTooltip);
|
||||
|
||||
_previousPictureSize = ctrlEventViewerPpuView.Size;
|
||||
_binder.AddBinding(nameof(DebugInfo.EventViewerShowNtscBorders), chkShowNtscBorders);
|
||||
|
||||
this.GetData();
|
||||
|
||||
|
@ -102,13 +85,24 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
DebugWorkspaceManager.GetWorkspace();
|
||||
|
||||
RestoreLocation(ConfigManager.Config.DebugInfo.EventViewerLocation);
|
||||
RestoreLocation(ConfigManager.Config.DebugInfo.EventViewerLocation, ConfigManager.Config.DebugInfo.EventViewerSize);
|
||||
|
||||
this._notifListener = new InteropEmu.NotificationListener(ConfigManager.Config.DebugInfo.DebugConsoleId);
|
||||
this._notifListener.OnNotification += this._notifListener_OnNotification;
|
||||
|
||||
InitShortcuts();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitShortcuts()
|
||||
{
|
||||
mnuZoomIn.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomIn));
|
||||
mnuZoomOut.InitShortcut(this, nameof(DebuggerShortcutsConfig.ZoomOut));
|
||||
|
||||
mnuZoomIn.Click += (s, evt) => ctrlEventViewerPpuView.ZoomIn();
|
||||
mnuZoomOut.Click += (s, evt) => ctrlEventViewerPpuView.ZoomOut();
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
|
@ -117,21 +111,10 @@ namespace Mesen.GUI.Debugger
|
|||
|
||||
_binder.UpdateObject();
|
||||
ConfigManager.Config.DebugInfo.EventViewerLocation = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Location : this.Location;
|
||||
ConfigManager.Config.DebugInfo.EventViewerSize = this.WindowState != FormWindowState.Normal ? this.RestoreBounds.Size : this.Size;
|
||||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleZoom) {
|
||||
ToggleZoom();
|
||||
return true;
|
||||
} else if(keyData == ConfigManager.Config.DebugInfo.Shortcuts.PpuViewer_ToggleView) {
|
||||
ToggleView();
|
||||
return true;
|
||||
}
|
||||
return base.ProcessCmdKey(ref msg, keyData);
|
||||
}
|
||||
|
||||
|
||||
private void _notifListener_OnNotification(InteropEmu.NotificationEventArgs e)
|
||||
{
|
||||
switch(e.NotificationType) {
|
||||
|
@ -202,69 +185,6 @@ namespace Mesen.GUI.Debugger
|
|||
}
|
||||
}
|
||||
|
||||
private void ctrlEventViewerPpuView_OnPictureResized(object sender, EventArgs e)
|
||||
{
|
||||
Size picSize = ctrlEventViewerPpuView.GetCompactSize(false);
|
||||
this.Size += (picSize - _previousPictureSize);
|
||||
_originalSize += (picSize - _previousPictureSize);
|
||||
ctrlEventViewerPpuView.Size += (picSize - _previousPictureSize);
|
||||
_previousPictureSize = picSize;
|
||||
}
|
||||
|
||||
private void ToggleView()
|
||||
{
|
||||
if(!_isCompact) {
|
||||
_isCompact = true;
|
||||
_originalSize = this.Size;
|
||||
|
||||
this.ClientSize = ctrlEventViewerPpuView.GetCompactSize(false) + new Size(3, menuStrip1.Height + 3);
|
||||
|
||||
this.Controls.Add(ctrlEventViewerPpuView);
|
||||
ctrlEventViewerPpuView.BringToFront();
|
||||
ctrlEventViewerPpuView.Dock = DockStyle.Fill;
|
||||
|
||||
tabMain.Visible = false;
|
||||
} else {
|
||||
_isCompact = false;
|
||||
this.Size = _originalSize;
|
||||
ctrlEventViewerPpuView.Dock = DockStyle.None;
|
||||
ctrlEventViewerPpuView.Size = ctrlEventViewerPpuView.GetCompactSize(false);
|
||||
tabMain.Visible = true;
|
||||
tpgPpuView.Controls.Add(ctrlEventViewerPpuView);
|
||||
}
|
||||
|
||||
btnToggleView.Image = _isCompact ? Properties.Resources.Expand : Properties.Resources.Collapse;
|
||||
RefreshViewer();
|
||||
}
|
||||
|
||||
private void ToggleZoom()
|
||||
{
|
||||
ICompactControl ctrl = ctrlEventViewerPpuView;
|
||||
|
||||
if(!_isZoomed) {
|
||||
Size pictureSize = ctrl.GetCompactSize(false);
|
||||
ctrl.ScaleImage(2);
|
||||
_isZoomed = true;
|
||||
} else {
|
||||
Size pictureSize = ctrl.GetCompactSize(false);
|
||||
Size halfSize = new Size(pictureSize.Width / 2, pictureSize.Height / 2);
|
||||
ctrl.ScaleImage(0.5);
|
||||
_isZoomed = false;
|
||||
}
|
||||
chkToggleZoom.Checked = _isZoomed;
|
||||
RefreshViewer();
|
||||
}
|
||||
|
||||
private void btnToggleView_Click(object sender, EventArgs e)
|
||||
{
|
||||
ToggleView();
|
||||
}
|
||||
|
||||
private void chkToggleZoom_Click(object sender, EventArgs e)
|
||||
{
|
||||
ToggleZoom();
|
||||
}
|
||||
|
||||
private void picColor_BackColorChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshViewer();
|
||||
|
|
|
@ -297,6 +297,9 @@
|
|||
<Compile Include="Controls\ctrlNsfPlayer.Designer.cs">
|
||||
<DependentUpon>ctrlNsfPlayer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ctrlPanel.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\ctrlRecentGames.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -445,6 +448,15 @@
|
|||
<Compile Include="Debugger\Controls\ctrlFlagStatus.Designer.cs">
|
||||
<DependentUpon>ctrlFlagStatus.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlImagePanel.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlImagePanel.Designer.cs">
|
||||
<DependentUpon>ctrlImagePanel.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlImageViewer.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debugger\Controls\ctrlLabelList.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
|
@ -1383,6 +1395,9 @@
|
|||
<EmbeddedResource Include="Debugger\Controls\ctrlEventViewerPpuView.resx">
|
||||
<DependentUpon>ctrlEventViewerPpuView.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlImagePanel.resx">
|
||||
<DependentUpon>ctrlImagePanel.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Debugger\Controls\ctrlScanlineCycleSelect.resx">
|
||||
<DependentUpon>ctrlScanlineCycleSelect.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -490,27 +490,31 @@ namespace Mesen.GUI
|
|||
return frameData;
|
||||
}
|
||||
|
||||
[DllImport(DLLPath)] private static extern UInt32 DebugGetDebugEventCount([MarshalAs(UnmanagedType.I1)]bool returnPreviousFrameData);
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetDebugEvents")] private static extern void DebugGetDebugEventsWrapper(IntPtr frameBuffer, IntPtr infoArray, ref UInt32 maxEventCount, [MarshalAs(UnmanagedType.I1)]bool returnPreviousFrameData);
|
||||
public static void DebugGetDebugEvents(bool returnPreviousFrameData, out byte[] pictureData, out DebugEventInfo[] debugEvents)
|
||||
[DllImport(DLLPath)] private static extern UInt32 GetDebugEventCount([MarshalAs(UnmanagedType.I1)]bool getPreviousFrameData);
|
||||
[DllImport(DLLPath, EntryPoint = "GetDebugEvents")] private static extern void GetDebugEventsWrapper([In, Out]DebugEventInfo[] eventArray, ref UInt32 maxEventCount, [MarshalAs(UnmanagedType.I1)]bool getPreviousFrameData);
|
||||
public static DebugEventInfo[] GetDebugEvents(bool getPreviousFrameData)
|
||||
{
|
||||
pictureData = new byte[256 * 240 * 4];
|
||||
UInt32 maxEventCount = DebugGetDebugEventCount(returnPreviousFrameData);
|
||||
debugEvents = new DebugEventInfo[maxEventCount];
|
||||
|
||||
GCHandle hPictureData = GCHandle.Alloc(pictureData, GCHandleType.Pinned);
|
||||
GCHandle hDebugEvents = GCHandle.Alloc(debugEvents, GCHandleType.Pinned);
|
||||
try {
|
||||
InteropEmu.DebugGetDebugEventsWrapper(hPictureData.AddrOfPinnedObject(), hDebugEvents.AddrOfPinnedObject(), ref maxEventCount, returnPreviousFrameData);
|
||||
} finally {
|
||||
hPictureData.Free();
|
||||
hDebugEvents.Free();
|
||||
}
|
||||
UInt32 maxEventCount = GetDebugEventCount(getPreviousFrameData);
|
||||
DebugEventInfo[] debugEvents = new DebugEventInfo[maxEventCount];
|
||||
|
||||
InteropEmu.GetDebugEventsWrapper(debugEvents, ref maxEventCount, getPreviousFrameData);
|
||||
if(maxEventCount < debugEvents.Length) {
|
||||
//Remove the excess from the array if needed
|
||||
Array.Resize(ref debugEvents, (int)maxEventCount);
|
||||
}
|
||||
|
||||
return debugEvents;
|
||||
}
|
||||
|
||||
[DllImport(DLLPath)] public static extern void GetEventViewerEvent(ref DebugEventInfo evtInfo, Int16 scanline, UInt16 cycle, EventViewerDisplayOptions options);
|
||||
[DllImport(DLLPath)] public static extern UInt32 TakeEventSnapshot(EventViewerDisplayOptions options);
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "GetEventViewerOutput")] private static extern void GetEventViewerOutputWrapper([In, Out]byte[] buffer, EventViewerDisplayOptions options);
|
||||
public static byte[] GetEventViewerOutput(UInt32 scanlineCount, EventViewerDisplayOptions options)
|
||||
{
|
||||
byte[] buffer = new byte[341 * 2 * scanlineCount * 2 * 4];
|
||||
InteropEmu.GetEventViewerOutputWrapper(buffer, options);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
[DllImport(DLLPath, EntryPoint = "DebugGetProfilerData")] private static extern void DebugGetProfilerDataWrapper(IntPtr profilerData, ProfilerDataType dataType);
|
||||
|
@ -1243,7 +1247,7 @@ namespace Mesen.GUI
|
|||
{
|
||||
public UInt16 Cycle;
|
||||
public Int16 Scanline;
|
||||
public UInt16 ProgramCounter;
|
||||
public UInt32 ProgramCounter;
|
||||
public UInt16 Address;
|
||||
public Int16 BreakpointId;
|
||||
public DebugEventType Type;
|
||||
|
@ -2156,6 +2160,41 @@ namespace Mesen.GUI
|
|||
public RecordMovieFrom RecordFrom;
|
||||
}
|
||||
|
||||
public struct EventViewerDisplayOptions
|
||||
{
|
||||
public UInt32 IrqColor;
|
||||
public UInt32 NmiColor;
|
||||
public UInt32 DmcDmaReadColor;
|
||||
public UInt32 SpriteZeroHitColor;
|
||||
public UInt32 BreakpointColor;
|
||||
public UInt32 MapperRegisterReadColor;
|
||||
public UInt32 MapperRegisterWriteColor;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public UInt32[] PpuRegisterReadColors;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public UInt32[] PpuRegisterWriteColor;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowMapperRegisterWrites;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowMapperRegisterReads;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] ShowPpuRegisterWrites;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] ShowPpuRegisterReads;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowNmi;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowIrq;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowDmcDmaReads;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowSpriteZeroHit;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowMarkedBreakpoints;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowPreviousFrameEvents;
|
||||
[MarshalAs(UnmanagedType.I1)] public bool ShowNtscBorders;
|
||||
}
|
||||
|
||||
public enum BreakpointType
|
||||
{
|
||||
Global = 0,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../Core/Assembler.h"
|
||||
#include "../Core/TraceLogger.h"
|
||||
#include "../Core/PerformanceTracker.h"
|
||||
#include "../Core/EventManager.h"
|
||||
#include "../Core/LuaScriptingContext.h"
|
||||
|
||||
enum class ConsoleId;
|
||||
|
@ -149,6 +150,9 @@ extern "C"
|
|||
DllExport const char* __stdcall DebugGetScriptLog(int32_t scriptId) { return GetDebugger()->GetScriptLog(scriptId); }
|
||||
DllExport void __stdcall DebugSetScriptTimeout(uint32_t timeout) { LuaScriptingContext::SetScriptTimeout(timeout); }
|
||||
|
||||
DllExport void __stdcall DebugGetDebugEvents(uint32_t* pictureBuffer, DebugEventInfo *infoArray, uint32_t &maxEventCount, bool returnPreviousFrameData) { GetDebugger()->GetDebugEvents(pictureBuffer, infoArray, maxEventCount, returnPreviousFrameData); }
|
||||
DllExport uint32_t __stdcall DebugGetDebugEventCount(bool returnPreviousFrameData) { return GetDebugger()->GetDebugEventCount(returnPreviousFrameData); }
|
||||
DllExport void __stdcall GetDebugEvents(DebugEventInfo *infoArray, uint32_t &maxEventCount, bool getPreviousFrameData) { GetDebugger()->GetEventManager()->GetEvents(infoArray, maxEventCount, getPreviousFrameData); }
|
||||
DllExport uint32_t __stdcall GetDebugEventCount(bool getPreviousFrameData) { return GetDebugger()->GetEventManager()->GetEventCount(getPreviousFrameData); }
|
||||
DllExport void __stdcall GetEventViewerOutput(uint32_t *buffer, EventViewerDisplayOptions options) { GetDebugger()->GetEventManager()->GetDisplayBuffer(buffer, options); }
|
||||
DllExport void __stdcall GetEventViewerEvent(DebugEventInfo *evtInfo, int16_t scanline, uint16_t cycle, EventViewerDisplayOptions options) { *evtInfo = GetDebugger()->GetEventManager()->GetEvent(scanline, cycle, options); }
|
||||
DllExport uint32_t __stdcall TakeEventSnapshot(EventViewerDisplayOptions options) { return GetDebugger()->GetEventManager()->TakeEventSnapshot(options); }
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue