Glass panel: double-buffer PaintPanel + suppress WM_ERASEBKGND (issue #13 partial)

The panel repainted control-by-control straight onto the window DC on a
100ms timer.  Compose to a memory bitmap + single BitBlt; erase suppressed.
NOT the whole fix: the reporter's flicker is monitor-dependent (clean on a
display without the game window) = D3D-vs-GDI presentation contention, plus
a 100ms-timer-vs-125ms-lamp-flash sampling beat -- directions filed on #13.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-20 07:45:43 -05:00
co-authored by Claude Fable 5
parent 0d032029a0
commit aa2432be7e
+21 -1
View File
@@ -243,11 +243,21 @@ static void
PaintPanel(HWND window)
{
PAINTSTRUCT paint;
HDC dc = BeginPaint(window, &paint);
HDC winDC = BeginPaint(window, &paint);
unsigned long tick = GetTickCount();
RECT client;
GetClientRect(window, &client);
// Issue #13 (flicker): the 100ms repaint timer redrew the panel
// control-by-control straight onto the window DC -- visible progressive
// flicker at 10 Hz. Compose the whole frame into a memory bitmap and
// blit it once (plus WM_ERASEBKGND suppressed in the wndproc). The
// drawing body below is untouched: `dc` is now the memory DC.
HDC dc = CreateCompatibleDC(winDC);
HBITMAP backing = CreateCompatibleBitmap(winDC,
client.right - client.left, client.bottom - client.top);
HBITMAP oldBacking = (HBITMAP)SelectObject(dc, backing);
HBRUSH background = CreateSolidBrush(RGB(28, 28, 28));
FillRect(dc, &client, background);
DeleteObject(background);
@@ -381,6 +391,13 @@ static void
}
}
// single blit of the composed frame (issue #13)
BitBlt(winDC, 0, 0, client.right - client.left, client.bottom - client.top,
dc, 0, 0, SRCCOPY);
SelectObject(dc, oldBacking);
DeleteObject(backing);
DeleteDC(dc);
EndPaint(window, &paint);
}
@@ -395,6 +412,9 @@ static LRESULT CALLBACK
PaintPanel(window);
return 0;
case WM_ERASEBKGND:
return 1; // issue #13: PaintPanel fills the frame itself (double-buffered)
case WM_TIMER:
if (wparam == RepaintTimerId)
{