From 7d112ce309deb6813da25f4dbdc0cede0d6a9445 Mon Sep 17 00:00:00 2001 From: Cyd Date: Tue, 4 Aug 2026 19:28:11 -0500 Subject: [PATCH] Glass panels: flash at full rate when unfocused + red Panic/Eject button Two glass-panel indicator fixes reported by playtesters. 1. FLASH SLOW UNLESS FOCUSED. The per-display panel windows repaint off a 62ms WM_TIMER, and Windows coalesces/throttles timer + paint messages for a window that is in the BACKGROUND (unfocused) -- so with the game window holding focus the panels' lamp flash (a repaint-driven animation) crawled, and giving a panel focus un-throttled it. (My earlier surround fix drew in the main D3D frame and never touched these separate windows.) New BTGlassPanels_Tick(), called once per frame from the main render loop (L4VIDEO), drives a synchronous InvalidateRect+UpdateWindow at the ~16Hz flash cadence -- the main loop runs every frame regardless of which window has focus, and the forced paint bypasses the throttled timer-message path. The WM_TIMER stays for its one-shot re-snap. 2. RED PANIC/EJECT. 0x3D is the Panic/Eject button; on the blue flight panel it was just another blue block. The shared flight-grid geometry (L4RIOBANK) now tags 0x3D as colorClass 0 (red); L4GLASSWIN's AdoptBank maps colorClass 0 -> ClrRed explicitly (the flight bank's ClrBlue default no longer swallows it), and the surround (L4VB16) already renders non-blue/yellow as red -- so the eject stands out red in both the surround and the exploded window. Verified: Release links clean (40 tolerated /FORCE externals only); exploded panels boot + run 13s no crash under the per-frame repaint pump; riobank dump confirms 0x3d class=0 (red), neighbours class=2 (blue). Co-Authored-By: Claude Opus 4.8 --- engine/MUNGA_L4/L4GLASSWIN.cpp | 44 +++++++++++++++++++++++++++++++++- engine/MUNGA_L4/L4RIOBANK.cpp | 5 +++- engine/MUNGA_L4/L4VIDEO.cpp | 11 +++++++++ engine/MUNGA_L4/l4glasswin.h | 10 ++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/engine/MUNGA_L4/L4GLASSWIN.cpp b/engine/MUNGA_L4/L4GLASSWIN.cpp index 6c1e816..95e6fb8 100644 --- a/engine/MUNGA_L4/L4GLASSWIN.cpp +++ b/engine/MUNGA_L4/L4GLASSWIN.cpp @@ -190,7 +190,9 @@ static void GButton &b = w.buttons[w.buttonCount++]; b.address = src.address; b.color = (src.colorClass == 1) ? ClrYellow - : (src.colorClass == 2) ? ClrBlue : color; + : (src.colorClass == 2) ? ClrBlue + : (src.colorClass == 0) ? ClrRed // 0 = red (MFD, and the red Panic/Eject 0x3D) + : color; b.rect.left = src.x + dx; b.rect.top = src.y + dy; b.rect.right = src.x + dx + src.w; @@ -1050,3 +1052,43 @@ void if (subFont) { DeleteObject(subFont); subFont = NULL; } if (gStage) { delete[] gStage; gStage = NULL; } } + +//########################################################################### +// Per-frame repaint pump (2026-08-04, "indicators flash slowly unless focused"). +// +// These windows repaint off a 62 ms WM_TIMER. Windows COALESCES/THROTTLES timer +// AND paint messages for a window that is in the BACKGROUND (not focused) -- so +// when the game window (or another app) holds focus, the panel's WM_TIMER slows +// to a crawl and the lamp FLASH (a repaint-driven animation: BTLampBrightnessOf +// alternates the shade off GetTickCount every paint) drags. Giving the panel +// focus un-throttles its timer, which is exactly what playtesters saw. +// +// Fix: drive the repaint from the MAIN render loop (BTGlassPanels_Tick, called +// once per frame from L4VIDEO), gated to the same ~16 Hz flash cadence. The main +// loop runs every frame while the game is up regardless of which window has focus, +// and InvalidateRect + UpdateWindow forces a SYNCHRONOUS WM_PAINT -- bypassing the +// throttled timer-message path entirely. The WM_TIMER stays (it still owns the +// one-shot re-snap); a focused window just repaints from whichever fires first. +//########################################################################### + +void + BTGlassPanels_Tick() +{ + if (gWinCount == 0) + return; + + static unsigned long sLastPaint = 0; + unsigned long now = GetTickCount(); + if (now - sLastPaint < (unsigned long)RepaintMilliseconds) + return; + sLastPaint = now; + + for (int i = 0; i < gWinCount; ++i) + { + if (gWins[i].hwnd != NULL) + { + InvalidateRect(gWins[i].hwnd, NULL, FALSE); + UpdateWindow(gWins[i].hwnd); // synchronous paint, not the throttled queue + } + } +} diff --git a/engine/MUNGA_L4/L4RIOBANK.cpp b/engine/MUNGA_L4/L4RIOBANK.cpp index c196f22..f1e991d 100644 --- a/engine/MUNGA_L4/L4RIOBANK.cpp +++ b/engine/MUNGA_L4/L4RIOBANK.cpp @@ -258,7 +258,10 @@ void int row = i / columns; int x = originX + column * (cw + gap); int y = originY + row * (ch + gap); - Push(out, baseAddress + i, x, y, cw, ch, 2, + // Flight blocks are blue (colorClass 2), EXCEPT the Panic/Eject at 0x3D: + // red (colorClass 0) so the eject stands out on the blue panel. + int cc = (baseAddress + i == 0x3D) ? 0 : 2; + Push(out, baseAddress + i, x, y, cw, ch, cc, (inert != 0) ? inert[i] : 0, (labels != 0) ? labels[i] : 0); GrowBounds(out, x, y, cw, ch); diff --git a/engine/MUNGA_L4/L4VIDEO.cpp b/engine/MUNGA_L4/L4VIDEO.cpp index 8461311..5e95d38 100644 --- a/engine/MUNGA_L4/L4VIDEO.cpp +++ b/engine/MUNGA_L4/L4VIDEO.cpp @@ -8952,6 +8952,17 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte extern void BTGaugeWindowRenderAndPresent(LPDIRECT3DDEVICE9 device); BTGaugeWindowRenderAndPresent(mDevice); +#ifdef BT_GLASS + // Drive the per-display glass panels' repaint from the (always-running) main + // loop so their lamp flash keeps animating when they're in the background -- + // Windows throttles an unfocused window's own WM_TIMER ("indicators flash + // slowly unless you focus that window"). No-op unless the panels are up. + { + extern void BTGlassPanels_Tick(); + BTGlassPanels_Tick(); + } +#endif + // DIAG (turn-hitch hunt): draw CPU is _rt0..here; Present blocks on the GPU. LARGE_INTEGER _rt1; QueryPerformanceCounter(&_rt1); // COCKPIT LETTERBOX: uniform-scale the canvas into the client (NULL = the diff --git a/engine/MUNGA_L4/l4glasswin.h b/engine/MUNGA_L4/l4glasswin.h index caec3df..5000a29 100644 --- a/engine/MUNGA_L4/l4glasswin.h +++ b/engine/MUNGA_L4/l4glasswin.h @@ -31,6 +31,16 @@ void void BTGlassPanels_Destroy(); +// +// Per-frame repaint pump. Call once per frame from the main render loop so the +// per-display windows' lamp flash keeps animating even when they are in the +// background (Windows throttles a background window's own WM_TIMER; this drives a +// synchronous repaint at the flash cadence instead). No-op unless the windows +// are up. See the note at the definition (L4GLASSWIN.cpp). +// +void + BTGlassPanels_Tick(); + // // True when BT_GLASS_PANELS mode is selected (default ON under `-platform // glass`, OFF otherwise). Read by the render loop / L4VB16 dev-composite to