From 8f5a632c327ad245d9bf5162d3cb495a8f34ba10 Mon Sep 17 00:00:00 2001 From: Nelson Gomez Date: Sat, 19 Oct 2024 01:31:39 -0700 Subject: [PATCH] Add a debug mode window to show game framebuffer I was trying to debug issues with rendering for dirty rectangles, so I added a window to show the contents of the framebuffer that backs the dirty rect system. The color output is wrong because OpenGL's pixels are BGR and I'm just rendering it to the HWND as RGB, but that doesn't really matter. --- scgl/cGDriver.h | 6 ++++ scgl/cGDriver_Init.cpp | 18 ++++++++++ scgl/cGDriver_Viewport.cpp | 47 ++++++++++++++++++++++++ scgl/ext/cGDriver_BufferRegions.cpp | 55 +++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/scgl/cGDriver.h b/scgl/cGDriver.h index 0345c71..fcc33f2 100644 --- a/scgl/cGDriver.h +++ b/scgl/cGDriver.h @@ -98,6 +98,12 @@ namespace nSCGL void* deviceContext; void* glContext; +#ifndef NDEBUG + void* secondaryWindow; + void* secondaryDeviceContext; + void* pixels; +#endif + private: void SetLastError(DriverError err); void DestroyOpenGLContext(); diff --git a/scgl/cGDriver_Init.cpp b/scgl/cGDriver_Init.cpp index 41df910..4a834b1 100644 --- a/scgl/cGDriver_Init.cpp +++ b/scgl/cGDriver_Init.cpp @@ -5,6 +5,24 @@ namespace nSCGL { bool cGDriver::Init(void) { +#ifndef NDEBUG + WNDCLASS wcDebug{}; + wcDebug.style = CS_OWNDC; + wcDebug.lpfnWndProc = DefWindowProcA; + wcDebug.hInstance = GetModuleHandle(nullptr); + wcDebug.lpszClassName = "GDriverClass--OpenGLDebug"; + + UnregisterClass(wcDebug.lpszClassName, nullptr); + + if (!RegisterClass(&wcDebug)) { + DWORD err = GetLastError(); + if (err != ERROR_CLASS_ALREADY_EXISTS) { + MessageBoxA(NULL, "Failed to set up an OpenGL debug window class", "SCGL failed to start", MB_ICONERROR); + return false; + } + } +#endif + // Create an invisible default window to set up an initial OpenGL context WNDCLASS wc{}; wc.style = CS_OWNDC; diff --git a/scgl/cGDriver_Viewport.cpp b/scgl/cGDriver_Viewport.cpp index e264d66..edd414a 100644 --- a/scgl/cGDriver_Viewport.cpp +++ b/scgl/cGDriver_Viewport.cpp @@ -207,6 +207,53 @@ namespace nSCGL return; } +#ifndef NDEBUG + { + HWND secondaryHwnd = CreateWindowExA( + dwExtStyle, + "GDriverClass--OpenGLDebug", + "GDriverWindow--OpenGLDebug", + (dwStyle) & ~(WS_EX_APPWINDOW | WS_POPUP), + wndRect.left, + wndRect.top, + wndRect.right - wndRect.left, + wndRect.bottom - wndRect.top, + nullptr, + nullptr, + GetModuleHandle(nullptr), + nullptr); + + if (secondaryHwnd == nullptr) { + DWORD error = GetLastError(); + MessageBoxA(NULL, "Failed to create window.", "SCGL video mode error", MB_ICONWARNING); + return; + } + + HDC secondaryDC = GetDC(secondaryHwnd); + secondaryWindow = secondaryHwnd; + secondaryDeviceContext = secondaryDC; + + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cAlphaBits = (newMode.depth == 32) ? 8 : 1; + pfd.cColorBits = (newMode.depth == 32) ? 24 : 15; + pfd.cDepthBits = (newMode.depth == 32) ? 24 : 16; + pfd.cStencilBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + + pixelFormat = ChoosePixelFormat(secondaryDC, &pfd); + + if (!SetPixelFormat(secondaryDC, pixelFormat, &pfd)) { + MessageBoxA(NULL, "Failed to set video mode on debug window.", "SCGL video mode error", MB_ICONWARNING); + } + + ShowWindow(secondaryHwnd, SW_SHOWNORMAL); + pixels = new char[3 * newMode.width * newMode.height]; + } +#endif + wglMakeCurrent(hdc, static_cast(glContext)); if (supportedExtensions.swapControl) { diff --git a/scgl/ext/cGDriver_BufferRegions.cpp b/scgl/ext/cGDriver_BufferRegions.cpp index a059c03..af0220e 100644 --- a/scgl/ext/cGDriver_BufferRegions.cpp +++ b/scgl/ext/cGDriver_BufferRegions.cpp @@ -101,6 +101,61 @@ namespace nSCGL glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, framebufferMasks[bufferRegionIndex], GL_NEAREST); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#ifndef NDEBUG + if (framebufferMasks[bufferRegionIndex] == GL_COLOR_BUFFER_BIT) + { + glFinish(); + + memset(pixels, 127, width * height * 3); + glReadPixels(srcX0, srcY0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + + InvalidateRect((HWND)secondaryWindow, nullptr, TRUE); + + PAINTSTRUCT ps; + DWORD dwError; + HDC hdc = BeginPaint((HWND)secondaryWindow, &ps); + + dwError = GetLastError(); + + BITMAPINFO bm; + bm.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bm.bmiHeader.biWidth = width; + bm.bmiHeader.biHeight = height; + bm.bmiHeader.biPlanes = 1; + bm.bmiHeader.biBitCount = 24; + bm.bmiHeader.biCompression = BI_RGB; + bm.bmiHeader.biSizeImage = 0; + bm.bmiHeader.biXPelsPerMeter = 2835; + bm.bmiHeader.biYPelsPerMeter = 2835; + bm.bmiHeader.biClrUsed = 0; + bm.bmiHeader.biClrImportant = 0; + bm.bmiColors->rgbBlue = 255; + bm.bmiColors->rgbGreen = 255; + bm.bmiColors->rgbRed = 255; + bm.bmiColors->rgbReserved = 0; + + dwError = ::SetDIBitsToDevice( + hdc, + dstX0, + windowHeight - dstY1, + width, + height, + 0, + 0, + 0, + height, + pixels, + &bm, + DIB_RGB_COLORS); + + dwError = GetLastError(); + + EndPaint((HWND)secondaryWindow, &ps); + + dwError = GetLastError(); + } +#endif + return true; }