diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 20c0b87dba..68e03debd2 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -38,9 +38,10 @@ enum GPUDebugBufferFormat { GPU_DBG_FORMAT_8888 = 3, GPU_DBG_FORMAT_INVALID = 0xFF, - // These don't, they're for depth buffers. + // These don't, they're for depth/stencil buffers. GPU_DBG_FORMAT_FLOAT = 0x10, GPU_DBG_FORMAT_16BIT = 0x11, + GPU_DBG_FORMAT_8BIT = 0x12, }; struct GPUDebugBuffer { @@ -170,6 +171,9 @@ public: virtual u32 GetVertexAddress() = 0; virtual u32 GetIndexAddress() = 0; virtual GPUgstate GetGState() = 0; + // Needs to be called from the GPU thread. + // Calling from a separate thread (e.g. UI) may fail. + virtual void SetCmdValue(u32 op) = 0; // Needs to be called from the GPU thread, so on the same thread as a notification is fine. // Calling from a separate thread (e.g. UI) may fail. diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 5fa7c7a82d..fa7add6596 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -386,10 +386,10 @@ void FramebufferManagerDX9::SetRenderFrameBuffer() { gstate_c.framebufChanged = false; // Get parameters - u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8); + u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.fbwidth & 0x3C0; - u32 z_address = (gstate.zbptr & 0xFFFFFF) | ((gstate.zbwidth & 0xFF0000) << 8); + u32 z_address = gstate.getDepthBufRawAddress(); int z_stride = gstate.zbwidth & 0x3C0; // Yeah this is not completely right. but it'll do for now. diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 08f19e7f84..e01c556cc4 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -516,10 +516,10 @@ void FramebufferManager::SetRenderFrameBuffer() { gstate_c.framebufChanged = false; // Get parameters - u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8); + u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.fbwidth & 0x3C0; - u32 z_address = (gstate.zbptr & 0xFFFFFF) | ((gstate.zbwidth & 0xFF0000) << 8); + u32 z_address = gstate.getDepthBufRawAddress(); int z_stride = gstate.zbwidth & 0x3C0; // Yeah this is not completely right. but it'll do for now. @@ -1402,7 +1402,7 @@ void FramebufferManager::Resized() { } bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer) { - u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8); + u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.fbwidth & 0x3C0; VirtualFramebuffer *vfb = currentRenderVfb_; @@ -1429,10 +1429,10 @@ bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer) { } bool FramebufferManager::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8); + u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.fbwidth & 0x3C0; - u32 z_address = (gstate.zbptr & 0xFFFFFF) | ((gstate.zbwidth & 0xFF0000) << 8); + u32 z_address = gstate.getDepthBufRawAddress(); int z_stride = gstate.zbwidth & 0x3C0; VirtualFramebuffer *vfb = currentRenderVfb_; @@ -1462,7 +1462,7 @@ bool FramebufferManager::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { } bool FramebufferManager::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8); + u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.fbwidth & 0x3C0; VirtualFramebuffer *vfb = currentRenderVfb_; @@ -1478,7 +1478,7 @@ bool FramebufferManager::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { } #ifndef USING_GLES2 - buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_16BIT, true); + buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_8BIT, true); if (vfb->fbo) fbo_bind_for_read(vfb->fbo); glReadBuffer(GL_STENCIL_ATTACHMENT); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d5138ba060..8a9a62db9b 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1100,9 +1100,10 @@ std::vector GPUCommon::DissassembleOpRange(u32 startpc, u32 endpc) { std::vector result; GPUDebugOp info; - u32 prev = Memory::Read_U32(startpc - 4); + // Don't trigger a pause. + u32 prev = Memory::IsValidAddress(startpc - 4) ? Memory::Read_U32(startpc - 4) : 0; for (u32 pc = startpc; pc < endpc; pc += 4) { - u32 op = Memory::Read_U32(pc); + u32 op = Memory::IsValidAddress(pc) ? Memory::Read_U32(pc) : 0; GeDisassembleOp(pc, op, prev, buffer); prev = op; @@ -1130,3 +1131,12 @@ u32 GPUCommon::GetIndexAddress() { GPUgstate GPUCommon::GetGState() { return gstate; } + +void GPUCommon::SetCmdValue(u32 op) { + u32 cmd = op >> 24; + u32 diff = op ^ gstate.cmdmem[cmd]; + + PreExecuteOp(op, diff); + gstate.cmdmem[cmd] = op; + ExecuteOp(op, diff); +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index aa5e28f06d..a8355828d3 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -152,6 +152,7 @@ public: virtual u32 GetVertexAddress(); virtual u32 GetIndexAddress(); virtual GPUgstate GetGState(); + virtual void SetCmdValue(u32 op); virtual DisplayList* getList(int listid) { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 2f4f0464f4..7652a7d6a0 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -212,8 +212,13 @@ struct GPUgstate float tgenMatrix[12]; float boneMatrix[12 * 8]; // Eight bone matrices. + u32 getFrameBufRawAddress() const { return (fbptr & 0xFFFFFF) | ((fbwidth & 0xFF0000) << 8); } + // 0x44000000 is uncached VRAM. + u32 getFrameBufAddress() const { return 0x44000000 | getFrameBufRawAddress(); } GEBufferFormat FrameBufFormat() const { return static_cast(framebufpixformat & 3); } int FrameBufStride() const { return fbwidth&0x7C0; } + u32 getDepthBufRawAddress() const { return (zbptr & 0xFFFFFF) | ((zbwidth & 0xFF0000) << 8); } + u32 getDepthBufAddress() const { return 0x44000000 | getDepthBufRawAddress(); } int DepthBufStride() const { return zbwidth&0x7C0; } // Pixel Pipeline diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 038fbae46d..4fcec22ec8 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -431,11 +431,11 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) break; case GE_CMD_FRAMEBUFPTR: - fb.data = Memory::GetPointer(0x44000000 | (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8)); + fb.data = Memory::GetPointer(gstate.getFrameBufAddress()); break; case GE_CMD_FRAMEBUFWIDTH: - fb.data = Memory::GetPointer(0x44000000 | (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8)); + fb.data = Memory::GetPointer(gstate.getFrameBufAddress()); break; case GE_CMD_FRAMEBUFPIXFORMAT: @@ -532,11 +532,11 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff) break; case GE_CMD_ZBUFPTR: - depthbuf.data = Memory::GetPointer(0x44000000 | (gstate.zbptr & 0xFFFFFF) | ((gstate.zbwidth & 0xFF0000) << 8)); + depthbuf.data = Memory::GetPointer(gstate.getDepthBufAddress()); break; case GE_CMD_ZBUFWIDTH: - depthbuf.data = Memory::GetPointer(0x44000000 | (gstate.zbptr & 0xFFFFFF) | ((gstate.zbwidth & 0xFF0000) << 8)); + depthbuf.data = Memory::GetPointer(gstate.getDepthBufAddress()); break; case GE_CMD_AMBIENTCOLOR: diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index 1a15448d7d..8b6a13fbc2 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -1,7 +1,8 @@ #include "Windows/GEDebugger/CtrlDisplayListView.h" -#include "Core/Config.h" #include "Windows/GEDebugger/GEDebugger.h" +#include "Windows/InputBox.h" #include "Windows/Main.h" +#include "Core/Config.h" #include const PTCHAR CtrlDisplayListView::windowClass = _T("CtrlDisplayListView"); @@ -166,6 +167,8 @@ void CtrlDisplayListView::onPaint(WPARAM wParam, LPARAM lParam) HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOP); + auto disasm = gpuDebug->DissassembleOpRange(windowStart, windowStart + (visibleRows + 2) * instructionSize); + for (int i = 0; i < visibleRows+2; i++) { unsigned int address=windowStart + i*instructionSize; @@ -210,7 +213,7 @@ void CtrlDisplayListView::onPaint(WPARAM wParam, LPARAM lParam) } SetTextColor(hdc,textColor); - GPUDebugOp op = gpuDebug->DissassembleOp(address); + GPUDebugOp op = i < (int)disasm.size() ? disasm[i] : GPUDebugOp(); char addressText[64]; sprintf(addressText,"%08X %08X",op.pc,op.op); @@ -328,7 +331,7 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) redraw(); } break; - case IDC_DEBUG_LIST_SETSTALL: + case ID_GEDBG_SETSTALLADDR: { gpuDebug->ResetListStall(list.id,curAddress); list.stall = curAddress; @@ -354,6 +357,24 @@ void CtrlDisplayListView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) redraw(); } break; + case ID_GEDBG_GOTOPC: + setCurAddress(list.pc); + scrollAddressIntoView(); + redraw(); + break; + case ID_GEDBG_GOTOADDR: + { + u32 newAddress = curAddress; + if (!InputBox_GetHex(GetModuleHandle(NULL), wnd, L"Address", curAddress, newAddress)) { + break; + } + if (Memory::IsValidAddress(newAddress)) { + setCurAddress(newAddress); + scrollAddressIntoView(); + redraw(); + } + } + break; } return; } diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index 0223283187..72d269f6a8 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -41,6 +41,7 @@ enum PauseAction { PAUSE_GETDEPTHBUF, PAUSE_GETSTENCILBUF, PAUSE_GETTEX, + PAUSE_SETCMDVALUE, }; static bool attached = false; @@ -65,6 +66,13 @@ static GPUDebugBuffer bufferFrame; static GPUDebugBuffer bufferDepth; static GPUDebugBuffer bufferStencil; static GPUDebugBuffer bufferTex; +static u32 pauseSetCmdValue; + +enum PrimaryDisplayType { + PRIMARY_FRAMEBUF, + PRIMARY_DEPTHBUF, + PRIMARY_STENCILBUF, +}; // TODO: Simplify and move out of windows stuff, just block in a common way for everyone. @@ -137,6 +145,13 @@ static void RunPauseAction() { case PAUSE_GETTEX: bufferResult = gpuDebug->GetCurrentTexture(bufferTex); break; + + case PAUSE_SETCMDVALUE: + gpuDebug->SetCmdValue(pauseSetCmdValue); + break; + + default: + ERROR_LOG(HLE, "Unsupported pause action, forgot to add it to the switch."); } actionWait.notify_one(); @@ -151,7 +166,7 @@ static void ForceUnpause() { } CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) - : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), primaryDisplay(PRIMARY_FRAMEBUF), frameWindow(NULL), texWindow(NULL) { + : Dialog((LPCSTR)IDD_GEDEBUGGER, _hInstance, _hParent), frameWindow(NULL), texWindow(NULL) { breakCmds.resize(256, false); Core_ListenShutdown(ForceUnpause); @@ -175,6 +190,14 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) HWND wnd = tabs->AddTabWindow(L"CtrlDisplayListView",L"Display List"); displayList = CtrlDisplayListView::getFrom(wnd); + fbTabs = new TabControl(GetDlgItem(m_hDlg, IDC_GEDBG_FBTABS)); + fbTabs->SetMinTabWidth(50); + // Must be in the same order as PrimaryDisplayType. + fbTabs->AddTab(NULL, L"Color"); + fbTabs->AddTab(NULL, L"Depth"); + fbTabs->AddTab(NULL, L"Stencil"); + fbTabs->ShowTab(0, true); + flags = new TabStateFlags(_hInstance, m_hDlg); tabs->AddTabDialog(flags, L"Flags"); @@ -201,28 +224,24 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent) } CGEDebugger::~CGEDebugger() { - delete frameWindow; - delete texWindow; - delete flags; delete lighting; delete textureState; delete settings; delete lists; delete tabs; + delete fbTabs; } void CGEDebugger::SetupPreviews() { if (frameWindow == NULL) { frameWindow = SimpleGLWindow::GetFrom(GetDlgItem(m_hDlg, IDC_GEDBG_FRAME)); frameWindow->Initialize(SimpleGLWindow::ALPHA_IGNORE | SimpleGLWindow::RESIZE_SHRINK_CENTER); - // TODO: Why doesn't this work? frameWindow->Clear(); } if (texWindow == NULL) { texWindow = SimpleGLWindow::GetFrom(GetDlgItem(m_hDlg, IDC_GEDBG_TEX)); texWindow->Initialize(SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_SHRINK_CENTER); - // TODO: Why doesn't this work? texWindow->Clear(); } } @@ -230,31 +249,42 @@ void CGEDebugger::SetupPreviews() { void CGEDebugger::UpdatePreviews() { // TODO: Do something different if not paused? + wchar_t desc[256]; GPUDebugBuffer *primaryBuffer = NULL; + GPUgstate state; bufferResult = false; - switch (primaryDisplay) { + + if (gpuDebug != NULL) { + state = gpuDebug->GetGState(); + } + + switch (PrimaryDisplayType(fbTabs->CurrentTabIndex())) { case PRIMARY_FRAMEBUF: SetPauseAction(PAUSE_GETFRAMEBUF); primaryBuffer = &bufferFrame; + _snwprintf(desc, ARRAY_SIZE(desc), L"Color: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight()); break; case PRIMARY_DEPTHBUF: SetPauseAction(PAUSE_GETDEPTHBUF); primaryBuffer = &bufferDepth; + _snwprintf(desc, ARRAY_SIZE(desc), L"Depth: 0x%08x (%dx%d)", state.getDepthBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight()); break; case PRIMARY_STENCILBUF: SetPauseAction(PAUSE_GETSTENCILBUF); primaryBuffer = &bufferStencil; + _snwprintf(desc, ARRAY_SIZE(desc), L"Stencil: 0x%08x (%dx%d)", state.getFrameBufRawAddress(), primaryBuffer->GetStride(), primaryBuffer->GetHeight()); break; } if (bufferResult && primaryBuffer != NULL) { auto fmt = SimpleGLWindow::Format(primaryBuffer->GetFormat()); frameWindow->Draw(primaryBuffer->GetData(), primaryBuffer->GetStride(), primaryBuffer->GetHeight(), primaryBuffer->GetFlipped(), fmt); + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, desc); } else { - ERROR_LOG(COMMON, "Unable to get buffer for main display."); frameWindow->Clear(); + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L"Failed"); } bufferResult = false; @@ -265,20 +295,25 @@ void CGEDebugger::UpdatePreviews() { texWindow->Draw(bufferTex.GetData(), bufferTex.GetStride(), bufferTex.GetHeight(), bufferTex.GetFlipped(), fmt); if (gpuDebug != NULL) { - auto state = gpuDebug->GetGState(); if (state.isTextureAlphaUsed()) { texWindow->SetFlags(SimpleGLWindow::ALPHA_BLEND | SimpleGLWindow::RESIZE_SHRINK_CENTER); } else { texWindow->SetFlags(SimpleGLWindow::RESIZE_SHRINK_CENTER); } + _snwprintf(desc, ARRAY_SIZE(desc), L"Texture: 0x%08x (%dx%d)", state.getTextureAddress(0), state.getTextureWidth(0), state.getTextureHeight(0)); + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, desc); } } else { - ERROR_LOG(COMMON, "Unable to get texture (may be no texture set.)"); texWindow->Clear(); + if (gpuDebug == NULL || state.isTextureMapEnabled()) { + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"Texture: failed"); + } else { + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L"Texture: disabled"); + } } DisplayList list; - if (gpuDebug->GetCurrentDisplayList(list)) { + if (gpuDebug != NULL && gpuDebug->GetCurrentDisplayList(list)) { displayList->setDisplayList(list); } @@ -357,6 +392,13 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_MAINTAB: tabs->HandleNotify(lParam); break; + case IDC_GEDBG_FBTABS: + fbTabs->HandleNotify(lParam); + // TODO: Move this somewhere... + if (attached && gpuDebug != NULL) { + UpdatePreviews(); + } + break; } break; @@ -378,6 +420,9 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { case IDC_GEDBG_RESUME: frameWindow->Clear(); texWindow->Clear(); + SetDlgItemText(m_hDlg, IDC_GEDBG_FRAMEBUFADDR, L""); + SetDlgItemText(m_hDlg, IDC_GEDBG_TEXADDR, L""); + // TODO: detach? Should probably have separate UI, or just on activate? breakNextOp = false; breakNextDraw = false; @@ -432,6 +477,13 @@ BOOL CGEDebugger::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) { SendMessage(m_hDlg,WM_COMMAND,IDC_GEDBG_RESUME,0); } break; + + case WM_GEDBG_SETCMDWPARAM: + { + pauseSetCmdValue = (u32)wParam; + SetPauseAction(PAUSE_SETCMDVALUE); + } + break; } return FALSE; diff --git a/Windows/GEDebugger/GEDebugger.h b/Windows/GEDebugger/GEDebugger.h index 53ae7e636f..a5eff0736e 100644 --- a/Windows/GEDebugger/GEDebugger.h +++ b/Windows/GEDebugger/GEDebugger.h @@ -29,7 +29,8 @@ enum { WM_GEDBG_BREAK_DRAW, WM_GEDBG_STEPDISPLAYLIST, WM_GEDBG_TOGGLEPCBREAKPOINT, - WM_GEDBG_RUNTOWPARAM + WM_GEDBG_RUNTOWPARAM, + WM_GEDBG_SETCMDWPARAM, }; class CtrlDisplayListView; @@ -61,13 +62,6 @@ private: void UpdateSize(WORD width, WORD height); void SavePosition(); - enum PrimaryDisplayType { - PRIMARY_FRAMEBUF, - PRIMARY_DEPTHBUF, - PRIMARY_STENCILBUF, - }; - - PrimaryDisplayType primaryDisplay; CtrlDisplayListView *displayList; TabDisplayLists *lists; TabStateFlags *flags; @@ -77,6 +71,7 @@ private: SimpleGLWindow *frameWindow; SimpleGLWindow *texWindow; TabControl *tabs; + TabControl *fbTabs; int minWidth,minHeight; }; diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index e404779972..2b329365ca 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -227,6 +227,9 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { } else if (fmt == FORMAT_16BIT) { glfmt = GL_UNSIGNED_SHORT; components = GL_RED; + } else if (fmt == FORMAT_8BIT) { + glfmt = GL_UNSIGNED_BYTE; + components = GL_RED; } else { _dbg_assert_msg_(COMMON, false, "Invalid SimpleGLWindow format."); } @@ -254,6 +257,11 @@ void SimpleGLWindow::Draw(u8 *data, int w, int h, bool flipped, Format fmt) { void SimpleGLWindow::Redraw() { DrawChecker(); + if (tw_ == 0 && th_ == 0) { + Swap(); + return; + } + if (flags_ & ALPHA_BLEND) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -306,8 +314,63 @@ void SimpleGLWindow::Redraw() { } void SimpleGLWindow::Clear() { - DrawChecker(); - Swap(); + tw_ = 0; + th_ = 0; + Redraw(); +} + +bool SimpleGLWindow::DragStart(int mouseX, int mouseY) { + // Only while zoomed in, otherwise it's shrink to fit mode or fixed. + if (!zoom_) { + return false; + } + + dragging_ = true; + SetCapture(hWnd_); + dragStartX_ = mouseX - offsetX_; + dragStartY_ = mouseY - offsetY_; + dragLastUpdate_ = GetTickCount(); + + return true; +} + +bool SimpleGLWindow::DragContinue(int mouseX, int mouseY) { + if (!dragging_) { + return false; + } + + offsetX_ = mouseX - dragStartX_; + offsetY_ = mouseY - dragStartY_; + + const u32 MS_BETWEEN_DRAG_REDRAWS = 5; + if (GetTickCount() - dragLastUpdate_ > MS_BETWEEN_DRAG_REDRAWS) { + Redraw(); + } + + return true; +} + +bool SimpleGLWindow::DragEnd(int mouseX, int mouseY) { + if (!dragging_) { + return false; + } + + dragging_ = false; + ReleaseCapture(); + Redraw(); + + return true; +} + +bool SimpleGLWindow::ToggleZoom() { + // Reset the offset when zooming out (or in, doesn't matter.) + offsetX_ = 0; + offsetY_ = 0; + + zoom_ = !zoom_; + Redraw(); + + return true; } SimpleGLWindow *SimpleGLWindow::GetFrom(HWND hwnd) { @@ -320,48 +383,42 @@ LRESULT CALLBACK SimpleGLWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPA switch(msg) { case WM_NCCREATE: - // Allocate a new CustCtrl structure for this window. win = new SimpleGLWindow(hwnd); // Continue with window creation. - return win != NULL; + return win != NULL ? TRUE : FALSE; + + case WM_NCDESTROY: + delete win; + return 0; case WM_LBUTTONDBLCLK: - win->zoom_ = !win->zoom_; - // Reset the offset when zooming out (or in, doesn't matter.) - win->offsetX_ = 0; - win->offsetY_ = 0; - // Redrawn in WM_LBUTTONUP. - return 0; - - case WM_LBUTTONDOWN: - // Only while zoomed in, otherwise it's shrink to fit mode or fixed. - if (win->zoom_) { - win->dragging_ = true; - win->dragStartX_ = GET_X_LPARAM(lParam) - win->offsetX_; - win->dragStartY_ = GET_Y_LPARAM(lParam) - win->offsetY_; - win->dragLastUpdate_ = GetTickCount(); - } - return 0; - - case WM_LBUTTONUP: - win->dragging_ = false; - win->Redraw(); - return 0; - - case WM_MOUSEMOVE: - if (win->dragging_) { - int x = GET_X_LPARAM(lParam); - int y = GET_Y_LPARAM(lParam); - win->offsetX_ = x - win->dragStartX_; - win->offsetY_ = y - win->dragStartY_; - const u32 MS_BETWEEN_DRAG_REDRAWS = 5; - if (GetTickCount() - win->dragLastUpdate_ > MS_BETWEEN_DRAG_REDRAWS) { - win->Redraw(); - } + if (win->ToggleZoom()) { return 0; } break; + + case WM_LBUTTONDOWN: + if (win->DragStart(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + return 0; + } + break; + + case WM_LBUTTONUP: + if (win->DragEnd(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + return 0; + } + break; + + case WM_MOUSEMOVE: + if (win->DragContinue(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) { + return 0; + } + break; + + case WM_PAINT: + win->Redraw(); + break; } return DefWindowProc(hwnd, msg, wParam, lParam); diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index d9739a6b54..97b36c8e53 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -32,6 +32,7 @@ struct SimpleGLWindow { FORMAT_FLOAT = 0x10, FORMAT_16BIT = 0x11, + FORMAT_8BIT = 0x12, }; enum Flags { @@ -68,6 +69,10 @@ protected: void CreateProgram(); void GenerateChecker(); void DrawChecker(); + bool DragStart(int mouseX, int mouseY); + bool DragContinue(int mouseX, int mouseY); + bool DragEnd(int mouseX, int mouseY); + bool ToggleZoom(); HWND hWnd_; HDC hDC_; diff --git a/Windows/GEDebugger/TabState.cpp b/Windows/GEDebugger/TabState.cpp index 17d8c9655c..baca3a3e39 100644 --- a/Windows/GEDebugger/TabState.cpp +++ b/Windows/GEDebugger/TabState.cpp @@ -17,6 +17,8 @@ #include "base/basictypes.h" #include "Windows/resource.h" +#include "Windows/InputBox.h" +#include "Windows/GEDebugger/GEDebugger.h" #include "Windows/GEDebugger/TabState.h" #include "GPU/GPUState.h" #include "GPU/GeDisasm.h" @@ -54,6 +56,7 @@ enum CmdFormatType { CMD_FMT_MATERIALUPDATE, CMD_FMT_STENCILOP, CMD_FMT_BLENDMODE, + CMD_FMT_FLAG, }; struct TabStateRow { @@ -66,25 +69,25 @@ struct TabStateRow { }; static const TabStateRow stateFlagsRows[] = { - { L"Lighting enable", GE_CMD_LIGHTINGENABLE, CMD_FMT_NUM }, - { L"Light 0 enable", GE_CMD_LIGHTENABLE0, CMD_FMT_NUM }, - { L"Light 1 enable", GE_CMD_LIGHTENABLE1, CMD_FMT_NUM }, - { L"Light 2 enable", GE_CMD_LIGHTENABLE2, CMD_FMT_NUM }, - { L"Light 3 enable", GE_CMD_LIGHTENABLE3, CMD_FMT_NUM }, - { L"Clip enable", GE_CMD_CLIPENABLE, CMD_FMT_NUM }, - { L"Cullface enable", GE_CMD_CULLFACEENABLE, CMD_FMT_NUM }, - { L"Texture map enable", GE_CMD_TEXTUREMAPENABLE, CMD_FMT_NUM }, - { L"Fog enable", GE_CMD_FOGENABLE, CMD_FMT_NUM }, - { L"Dither enable", GE_CMD_DITHERENABLE, CMD_FMT_NUM }, - { L"Alpha blend enable", GE_CMD_ALPHABLENDENABLE, CMD_FMT_NUM }, - { L"Alpha test enable", GE_CMD_ALPHATESTENABLE, CMD_FMT_NUM }, - { L"Depth test enable", GE_CMD_ZTESTENABLE, CMD_FMT_NUM }, - { L"Stencil test enable", GE_CMD_STENCILTESTENABLE, CMD_FMT_NUM }, - { L"Antialias enable", GE_CMD_ANTIALIASENABLE, CMD_FMT_NUM }, - { L"Patch cull enable", GE_CMD_PATCHCULLENABLE, CMD_FMT_NUM }, - { L"Color test enable", GE_CMD_COLORTESTENABLE, CMD_FMT_NUM }, - { L"Logic op enable", GE_CMD_LOGICOPENABLE, CMD_FMT_NUM }, - { L"Depth write disable", GE_CMD_ZWRITEDISABLE, CMD_FMT_NUM }, + { L"Lighting enable", GE_CMD_LIGHTINGENABLE, CMD_FMT_FLAG }, + { L"Light 0 enable", GE_CMD_LIGHTENABLE0, CMD_FMT_FLAG }, + { L"Light 1 enable", GE_CMD_LIGHTENABLE1, CMD_FMT_FLAG }, + { L"Light 2 enable", GE_CMD_LIGHTENABLE2, CMD_FMT_FLAG }, + { L"Light 3 enable", GE_CMD_LIGHTENABLE3, CMD_FMT_FLAG }, + { L"Clip enable", GE_CMD_CLIPENABLE, CMD_FMT_FLAG }, + { L"Cullface enable", GE_CMD_CULLFACEENABLE, CMD_FMT_FLAG }, + { L"Texture map enable", GE_CMD_TEXTUREMAPENABLE, CMD_FMT_FLAG }, + { L"Fog enable", GE_CMD_FOGENABLE, CMD_FMT_FLAG }, + { L"Dither enable", GE_CMD_DITHERENABLE, CMD_FMT_FLAG }, + { L"Alpha blend enable", GE_CMD_ALPHABLENDENABLE, CMD_FMT_FLAG }, + { L"Alpha test enable", GE_CMD_ALPHATESTENABLE, CMD_FMT_FLAG }, + { L"Depth test enable", GE_CMD_ZTESTENABLE, CMD_FMT_FLAG }, + { L"Stencil test enable", GE_CMD_STENCILTESTENABLE, CMD_FMT_FLAG }, + { L"Antialias enable", GE_CMD_ANTIALIASENABLE, CMD_FMT_FLAG }, + { L"Patch cull enable", GE_CMD_PATCHCULLENABLE, CMD_FMT_FLAG }, + { L"Color test enable", GE_CMD_COLORTESTENABLE, CMD_FMT_FLAG }, + { L"Logic op enable", GE_CMD_LOGICOPENABLE, CMD_FMT_FLAG }, + { L"Depth write disable", GE_CMD_ZWRITEDISABLE, CMD_FMT_FLAG }, }; static const TabStateRow stateLightingRows[] = { @@ -97,7 +100,7 @@ static const TabStateRow stateLightingRows[] = { { L"Material alpha", GE_CMD_MATERIALALPHA, CMD_FMT_HEX }, { L"Material specular", GE_CMD_MATERIALSPECULAR, CMD_FMT_HEX }, { L"Mat. specular coef", GE_CMD_MATERIALSPECULARCOEF, CMD_FMT_FLOAT24 }, - { L"Reverse normals", GE_CMD_REVERSENORMAL, CMD_FMT_NUM }, + { L"Reverse normals", GE_CMD_REVERSENORMAL, CMD_FMT_FLAG }, // TODO: Format? { L"Shade model", GE_CMD_SHADEMODE, CMD_FMT_NUM }, // TODO: Format? @@ -484,6 +487,14 @@ void FormatStateRow(wchar_t *dest, const TabStateRow &info, u32 value, bool enab } break; + case CMD_FMT_FLAG: + if ((value & ~1) == 0) { + swprintf(dest, L"%d", value); + } else { + swprintf(dest, L"%06x", value); + } + break; + default: swprintf(dest, L"BAD FORMAT %06x", value); } @@ -518,7 +529,48 @@ void CtrlStateValues::GetColumnText(wchar_t *dest, int row, int col) { break; } } - +} + +void CtrlStateValues::OnDoubleClick(int row, int column) { + if (gpuDebug == NULL) { + return; + } + + const auto info = rows_[row]; + switch (info.fmt) { + case CMD_FMT_FLAG: + { + const auto state = gpuDebug->GetGState(); + u32 newValue = state.cmdmem[info.cmd] ^ 1; + SetCmdValue(newValue); + } + break; + + default: + { + // TODO: Floats/etc., and things with multiple cmds. + const auto state = gpuDebug->GetGState(); + u32 newValue = state.cmdmem[info.cmd] & 0x00FFFFFF; + if (InputBox_GetHex(GetModuleHandle(NULL), GetHandle(), L"New value", newValue, newValue)) { + newValue |= state.cmdmem[info.cmd] & 0xFF000000; + SetCmdValue(newValue); + } + } + break; + } +} + +void CtrlStateValues::OnRightClick(int row, int column, const POINT& point) { + if (gpuDebug == NULL) { + return; + } + + // TODO: Copy, break, watch... enable? +} + +void CtrlStateValues::SetCmdValue(u32 op) { + SendMessage(GetParent(GetParent(GetHandle())), WM_GEDBG_SETCMDWPARAM, op, NULL); + Update(); } TabStateValues::TabStateValues(const TabStateRow *rows, int rowCount, LPCSTR dialogID, HINSTANCE _hInstance, HWND _hParent) diff --git a/Windows/GEDebugger/TabState.h b/Windows/GEDebugger/TabState.h index e86b693199..c31ef8bfe3 100644 --- a/Windows/GEDebugger/TabState.h +++ b/Windows/GEDebugger/TabState.h @@ -30,8 +30,12 @@ protected: virtual bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue) { return false; }; virtual void GetColumnText(wchar_t* dest, int row, int col); virtual int GetRowCount() { return rowCount_; } + virtual void OnDoubleClick(int row, int column); + virtual void OnRightClick(int row, int column, const POINT& point); private: + void SetCmdValue(u32 op); + const TabStateRow *rows_; int rowCount_; }; diff --git a/Windows/InputBox.cpp b/Windows/InputBox.cpp index 7d24b4f2b4..bb840adb8d 100644 --- a/Windows/InputBox.cpp +++ b/Windows/InputBox.cpp @@ -117,8 +117,11 @@ bool InputBox_GetHex(HINSTANCE hInst, HWND hParent, const wchar_t *title, u32 de if (value == IDOK) { - wscanf(out.c_str(),"%08x",&outvalue); - return true; + if (swscanf(out.c_str(), L"0x%08x", &outvalue) == 1) + return true; + if (swscanf(out.c_str(), L"%08x", &outvalue) == 1) + return true; + return false; } else { diff --git a/Windows/W32Util/TabControl.cpp b/Windows/W32Util/TabControl.cpp index 8c55ad2194..7937dce26b 100644 --- a/Windows/W32Util/TabControl.cpp +++ b/Windows/W32Util/TabControl.cpp @@ -6,7 +6,8 @@ const DWORD tabControlStyleMask = ~(WS_POPUP | WS_TILEDWINDOW); -TabControl::TabControl(HWND handle): hwnd(handle), showTabTitles(true),currentTab(0),ignoreBottomMargin(false) +TabControl::TabControl(HWND handle, bool noDisplayArea) + : hwnd(handle), showTabTitles(true), currentTab(0), ignoreBottomMargin(false), noDisplayArea_(noDisplayArea) { SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)this); oldProc = (WNDPROC) SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)wndProc); @@ -60,26 +61,29 @@ void TabControl::AddTab(HWND handle, wchar_t* title) if (showTabTitles) AppendPageToControl(title); int index = tabs.size(); - - RECT tabRect; - GetWindowRect(hwnd,&tabRect); - MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2); - TabCtrl_AdjustRect(hwnd, FALSE, &tabRect); - SetParent(handle,GetParent(hwnd)); - DWORD style = (GetWindowLong(handle,GWL_STYLE) | WS_CHILD); - - TabInfo info; - info.hasBorder = (style & WS_BORDER) != 0; - info.hasClientEdge = (GetWindowLong(handle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0; - if (hasButtons == false) + TabInfo info = {0}; + if (!noDisplayArea_) { - style &= (~WS_BORDER); - SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE)); - } + RECT tabRect; + GetWindowRect(hwnd,&tabRect); + MapWindowPoints(HWND_DESKTOP,GetParent(hwnd),(LPPOINT)&tabRect,2); + TabCtrl_AdjustRect(hwnd, FALSE, &tabRect); - SetWindowLong(handle, GWL_STYLE, style & tabControlStyleMask); - MoveWindow(handle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); + SetParent(handle,GetParent(hwnd)); + DWORD style = (GetWindowLong(handle,GWL_STYLE) | WS_CHILD); + + info.hasBorder = (style & WS_BORDER) != 0; + info.hasClientEdge = (GetWindowLong(handle,GWL_EXSTYLE) & WS_EX_CLIENTEDGE) != 0; + if (hasButtons == false) + { + style &= (~WS_BORDER); + SetWindowLong(handle, GWL_EXSTYLE, GetWindowLong(handle,GWL_EXSTYLE) & (~WS_EX_CLIENTEDGE)); + } + + SetWindowLong(handle, GWL_STYLE, style & tabControlStyleMask); + MoveWindow(handle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); + } info.lastFocus = handle; info.pageHandle = handle; @@ -133,7 +137,8 @@ void TabControl::ShowTab(int index, bool setControlIndex) { if (oldFocus && i == index) SetFocus(tabs[i].lastFocus); - ShowWindow(tabs[i].pageHandle,i == index ? SW_NORMAL : SW_HIDE); + if (!noDisplayArea_) + ShowWindow(tabs[i].pageHandle,i == index ? SW_NORMAL : SW_HIDE); } if (setControlIndex && showTabTitles) @@ -156,7 +161,8 @@ void TabControl::ShowTab(HWND pageHandle) if (oldFocus) SetFocus(tabs[i].lastFocus); } - ShowWindow(tabs[i].pageHandle,tabs[i].pageHandle == pageHandle ? SW_NORMAL : SW_HIDE); + if (!noDisplayArea_) + ShowWindow(tabs[i].pageHandle,tabs[i].pageHandle == pageHandle ? SW_NORMAL : SW_HIDE); } } @@ -176,7 +182,7 @@ void TabControl::SetShowTabTitles(bool enabled) { AppendPageToControl(tabs[i].title); - if (hasButtons == false) + if (hasButtons == false && !noDisplayArea_) { DWORD style = GetWindowLong(tabs[i].pageHandle,GWL_STYLE) & (~WS_BORDER); SetWindowLong(tabs[i].pageHandle,GWL_STYLE,style); @@ -186,7 +192,7 @@ void TabControl::SetShowTabTitles(bool enabled) } } TabCtrl_SetCurSel(hwnd,CurrentTabIndex()); - } else if (hasButtons == false) + } else if (hasButtons == false && !noDisplayArea_) { for (int i = 0; i < (int) tabs.size(); i++) { @@ -207,6 +213,11 @@ void TabControl::SetShowTabTitles(bool enabled) OnResize(); } +void TabControl::SetMinTabWidth(int w) +{ + TabCtrl_SetMinTabWidth(hwnd, w); +} + void TabControl::NextTab(bool cycle) { int index = CurrentTabIndex()+1; @@ -265,15 +276,18 @@ void TabControl::OnResize() int current = CurrentTabIndex(); - for (size_t i = 0; i < tabs.size(); i++) + if (!noDisplayArea_) { - InvalidateRect(tabs[i].pageHandle,NULL,FALSE); - MoveWindow(tabs[i].pageHandle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); - - if (i == current) + for (size_t i = 0; i < tabs.size(); i++) { - InvalidateRect(tabs[i].pageHandle,NULL,TRUE); - UpdateWindow(tabs[i].pageHandle); + InvalidateRect(tabs[i].pageHandle,NULL,FALSE); + MoveWindow(tabs[i].pageHandle,tabRect.left,tabRect.top,tabRect.right-tabRect.left,tabRect.bottom-tabRect.top,TRUE); + + if (i == current) + { + InvalidateRect(tabs[i].pageHandle,NULL,TRUE); + UpdateWindow(tabs[i].pageHandle); + } } } } diff --git a/Windows/W32Util/TabControl.h b/Windows/W32Util/TabControl.h index 94f0d4b349..489bb55ae9 100644 --- a/Windows/W32Util/TabControl.h +++ b/Windows/W32Util/TabControl.h @@ -7,7 +7,7 @@ class Dialog; class TabControl { public: - TabControl(HWND handle); + TabControl(HWND handle, bool noDisplayArea = false); void HandleNotify(LPARAM lParam); HWND AddTabWindow(wchar_t* className, wchar_t* title, DWORD style = 0); void AddTabDialog(Dialog* dialog, wchar_t* title); @@ -21,6 +21,8 @@ public: void SetShowTabTitles(bool enabled); void SetIgnoreBottomMargin(bool enabled) { ignoreBottomMargin = enabled; }; bool GetShowTabTitles() { return showTabTitles; }; + void SetMinTabWidth(int w); + private: static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); void OnResize(); @@ -42,4 +44,5 @@ private: bool ignoreBottomMargin; int currentTab; bool hasButtons; + bool noDisplayArea_; }; \ No newline at end of file diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 6dfd2910b0..80c71402bb 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -178,7 +178,10 @@ BEGIN PUSHBUTTON "Resume",IDC_GEDBG_RESUME,104,0,48,14 CONTROL "",IDC_GEDBG_TEX,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,10,20,128,128 CONTROL "",IDC_GEDBG_FRAME,"SimpleGLWindow",WS_CHILD | WS_VISIBLE,148,20,256,136 - CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER ,10,216,480,180 + CONTROL "",IDC_GEDBG_MAINTAB,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,10,216,480,180 + EDITTEXT IDC_GEDBG_FRAMEBUFADDR,148,192,128,12,ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_GEDBG_TEXADDR,10,152,128,12,ES_READONLY | NOT WS_BORDER + CONTROL "",IDC_GEDBG_FBTABS,"SysTabControl32",TCS_BUTTONS | TCS_FOCUSNEVER,384,192,110,12 END @@ -505,7 +508,7 @@ BEGIN MENUITEM "Copy Instruction (Disasm)", ID_DISASM_COPYINSTRUCTIONDISASM MENUITEM "Disassemble to File", ID_DISASM_DISASSEMBLETOFILE MENUITEM SEPARATOR - MENUITEM "Assemble Ppcode", ID_DISASM_ASSEMBLE + MENUITEM "Assemble Opcode", ID_DISASM_ASSEMBLE MENUITEM SEPARATOR MENUITEM "Run to Cursor", ID_DISASM_RUNTOHERE MENUITEM "Jump to Cursor", ID_DISASM_SETPCTOHERE @@ -558,9 +561,11 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Run to Cursor", ID_DISASM_RUNTOHERE MENUITEM "Jump to Cursor", ID_DISASM_SETPCTOHERE - MENUITEM "Set Stall" IDC_DEBUG_LIST_SETSTALL + MENUITEM "Set Stall" ID_GEDBG_SETSTALLADDR MENUITEM "Toggle Breakpoint", ID_DISASM_TOGGLEBREAKPOINT MENUITEM SEPARATOR + MENUITEM "Go to Displaylist PC", ID_GEDBG_GOTOPC + MENUITEM "Go to Address...", ID_GEDBG_GOTOADDR MENUITEM "Go to in Memory View", ID_DISASM_GOTOINMEMORYVIEW END END diff --git a/Windows/resource.h b/Windows/resource.h index 603b7c8161..4fc81fafa0 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -155,6 +155,9 @@ #define IDC_DUMP_SIZE 1188 #define IDC_DUMP_FILENAME 1189 #define IDC_DUMP_BROWSEFILENAME 1190 +#define IDC_GEDBG_FRAMEBUFADDR 1191 +#define IDC_GEDBG_TEXADDR 1192 +#define IDC_GEDBG_FBTABS 1193 // Don't define anything else in the 3000 range. // It's reserved for languages. @@ -284,7 +287,9 @@ #define IDC_DEBUG_BOTTOMTABS 40127 #define ID_DEBUG_HIDEBOTTOMTABS 40128 #define ID_DEBUG_TOGGLEBOTTOMTABTITLES 40129 -#define IDC_DEBUG_LIST_SETSTALL 40130 +#define ID_GEDBG_SETSTALLADDR 40130 +#define ID_GEDBG_GOTOPC 40131 +#define ID_GEDBG_GOTOADDR 40132 // Dummy option to let the buffered rendering hotkey cycle through all the options. #define ID_OPTIONS_BUFFEREDRENDERINGDUMMY 40500 @@ -297,8 +302,8 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 254 -#define _APS_NEXT_COMMAND_VALUE 40131 -#define _APS_NEXT_CONTROL_VALUE 1191 +#define _APS_NEXT_COMMAND_VALUE 40133 +#define _APS_NEXT_CONTROL_VALUE 1193 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif