Glass cockpit: per-display windows (BT_GLASS_PANELS)
Break the desktop glass cockpit's secondary displays out of the single combined pad panel + D3D gauge strip into ONE window per pod display, each carrying that display's surface with its RIO button bank, arranged pod-faithfully around the main view. New TU engine/MUNGA_L4/L4GLASSWIN.* (BT_GLASS-only), selected by the -platform glass preset via the new runtime gate BT_GLASS_PANELS (=0 falls back to the legacy single panel + dock). - Surfaces are CPU-expanded from the shared gauge buffer (SVGA16::ExpandPlaneToBGRA, no D3D) and StretchDIBits'd in -- the D3D dev-composite path (dock / window / overlay) stands down while active. - Buttons sit UNDER the imagery: big hidden click targets that reach into the display, with only a small protruding edge showing as a lamp light. Red MFD banks tile the top/bottom; radar rails run the sides + a bottom row; a Flight Controls window hosts the no-display banks. - Windows: Heat / Engineering / Comm / Left Weapons / Right Weapons / radar + Flight Controls; edge-to-edge (no in-client margin/title; OS caption labels each). - Fix blank surfaces: application/ghWnd are duplicate-defined and bind non-deterministically under /FORCE, so the fresh L4GLASSWIN TU read NULL. Reach the renderer/window via BTResolveGaugeRenderer/BTResolveMainWindow defined in btl4main.cpp off the real btl4App/hWnd pointers. New gotcha: reconstruction-gotchas.md S6 duplicate-GLOBAL corollary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -285,3 +285,93 @@ cavern.egg`. This is every option the original console exposed for a BattleTech
|
||||
- dropzone (5, the `dropzone=` field): one, two, three, four, five ← was `one`
|
||||
- advancedDamage (0/1): the advanced damage model toggle ← was hardcoded `1`
|
||||
- vehicleValue: 1000 (const), loadzones=1 (const), bitmapindex (per-pilot ordinal)
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-20 — Per-display cockpit windows (BT_GLASS_PANELS)
|
||||
|
||||
**Goal (Cyd):** stop collapsing the desktop cockpit into combined surfaces. Break each
|
||||
SECONDARY display out into its OWN window carrying that display's surface WITH its RIO button
|
||||
bank placed around it, arranged pod-faithfully around the main 3D view — a dev cockpit that
|
||||
reads like the pod, so button/lamp/display behavior can be validated in position.
|
||||
|
||||
**New TU: `engine/MUNGA_L4/L4GLASSWIN.{h,cpp}`** (BT_GLASS-only; added to the CMake BT_GLASS
|
||||
`target_sources`). Builds SEVEN GDI windows and positions them around the main window:
|
||||
|
||||
| Window | Surface (port) | RIO bank | Buttons |
|
||||
|---|---|---|---|
|
||||
| Heat MFD (UL) | `Heat` (0x4000) | 0x28-0x2F | 8 red, 4 above / 4 below |
|
||||
| MFD 2 (UC) | `Mfd2`/`Eng2` (0x0400) | 0x20-0x27 | 8 red, 4 above / 4 below |
|
||||
| Comm MFD (UR) | `Comm` (0x8000) | 0x30-0x37 | 8 red, 4 above / 4 below |
|
||||
| MFD 1 (LL) | `Mfd1`/`Eng1` (0x0100) | 0x08-0x0F | 8 red, 4 above / 4 below |
|
||||
| MFD 3 (LR) | `Mfd3`/`Eng3` (0x1000) | 0x00-0x07 | 8 red, 4 above / 4 below |
|
||||
| Secondary/Radar | `sec` (palette, portrait) | 0x10-0x1B Secondary | 12 yellow, 6 left / 6 right |
|
||||
| Flight Controls | (none) | 0x38-0x47 (+ panic/icom) | neutral, 2 columns |
|
||||
|
||||
**Architecture — GDI + CPU blit, NO D3D for the secondaries.** Each window is a layered,
|
||||
topmost GDI window (the L4PADPANEL pattern: double-buffered paint, ~62 ms repaint timer,
|
||||
left-click = momentary / right-click = latch → `PadRIO::SetScreenButton`; lamps from
|
||||
`PadRIO::GetLampState`). The surface is CPU-expanded from the shared gauge pixelBuffer by the
|
||||
new **`SVGA16::ExpandPlaneToBGRA(mask, paletteID, monoTint, rotateQuadrant, dst, &ow, &oh)`**
|
||||
(L4VB16.cpp) — the no-D3D analog of `DrawDevSurface`: palette-LUT expand for `sec` (monoTint
|
||||
< 0), mono bit-plane → tint for the MFDs; the portrait secondary CRT is unrotated by
|
||||
transposing into `dst` (rotate 1/3, `BT_GAUGE_SEC_ROT`) — then `StretchDIBits` (HALFTONE) into
|
||||
the surface rect. An Mfd/Eng pair shows whichever plane is the live (non-`BlankColor`) one, as
|
||||
on the pod monitor. This reuses the plasma-window CPU→window pattern and sidesteps the whole
|
||||
D3D dev-composite bug family (additional-swap-chain lifetime, device-state save/restore,
|
||||
depth-stencil mismatch, layered strobing).
|
||||
|
||||
**Gate: `BT_GLASS_PANELS`** (runtime env; `BTGlassPanelsActive()`). Default ON under
|
||||
`-platform glass` (preset putenv in `btl4main.cpp`); `=0` restores the legacy single pad panel
|
||||
+ docked gauge strip. Wired at three seams:
|
||||
- `L4PADRIO` ctor: `BTGlassPanelsActive()` → `BTGlassPanels_Create()` instead of
|
||||
`BTPadPanel_Create()`; dtor destroys both (safe no-ops).
|
||||
- `L4VB16`: `BTDrawGaugeInset` / `BTGaugeWindowRenderAndPresent` early-return when
|
||||
`GlassPanelsOwnSurfaces()` (the per-display windows own the surfaces).
|
||||
- `btl4main`: skip the `gBTGaugeDockBottom` + 1100×600 world-window forcing (world stays
|
||||
normal size — no bottom strip).
|
||||
|
||||
**Placement.** `ComputeLayout()` rings the windows around `ghWnd` (the main game window):
|
||||
top row Heat/Mfd2/Comm above it, Mfd1/Mfd3 at the lower corners, radar below-center, Flight
|
||||
Controls left of the seat; clamped to the work area, with an 800×600-centered fallback before
|
||||
the main window exists + a one-shot reposition once `ghWnd` comes up (in the repaint timer).
|
||||
|
||||
**Verified [T2 startup].** `-DBT_GLASS=ON` Debug build links (the usual `/FORCE` mech3
|
||||
subsystem set is pre-existing, unrelated). Bounded `-platform glass -egg DEV.EGG` launch:
|
||||
`[glasswin] per-display cockpit up (7 windows: 5 MFD + radar + flight)`, `[plasmawin] … up`,
|
||||
`[padrio] XInput pad found`, no failure/abort markers, full mission loop un-regressed (killed
|
||||
after 18 s). Visual layout / surface content / click-through NOT yet human-verified.
|
||||
|
||||
**Tunable (Cyd flagged refinements):** surface display sizes, the exact button sub-positions
|
||||
around each screen, the yellow left/right split (first cut 0x10-0x15 / 0x16-0x1B), and the MFD
|
||||
mono phosphor tint — all named constants at the top of `L4GLASSWIN.cpp`. Deferred: folding the
|
||||
plasma window into the same arrangement; per-window draggable/saved positions; moving/resizing
|
||||
the main window into a true center cell for a tighter ring.
|
||||
|
||||
### Blank-surface bug (found + fixed same day) — /FORCE duplicate-global race
|
||||
|
||||
First glass-panels run showed the buttons but BLANK display surfaces. `BT_GLASS_LOG`
|
||||
diagnostics in `BlitSurface` traced it stage by stage: `application == 0x00000000` in
|
||||
`L4GLASSWIN.cpp` for the ENTIRE run (call 1 → 481), so `application->GetGaugeRenderer()` was
|
||||
never even reached. Yet the legacy dock path (`BTDrawGaugeSurfaces`, `L4VB16.cpp`, SAME engine
|
||||
lib) logged `application=047BA9C8 gr=0C57FF78` — non-NULL.
|
||||
|
||||
Root cause: the 1995 headers declare free globals (`application`, `ghWnd`, …) without
|
||||
`inline`/`extern`, so they are DEFINED in both `munga_engine` and `bt410_l4`. Under
|
||||
`/FORCE:MULTIPLE` the linker binds each `.obj`'s reference to one copy or the other
|
||||
**non-deterministically per link** — the newly-added `L4GLASSWIN.obj` bound the copy the game
|
||||
never assigns (stays NULL), and a relink even flipped `L4VB16.obj`. Routing through an engine
|
||||
helper is therefore unreliable (its binding is equally random).
|
||||
|
||||
Fix: `BTResolveGaugeRenderer()` / `BTResolveMainWindow()` (declared in `l4vb16.h`) are DEFINED
|
||||
in `game/btl4main.cpp` off the launcher's OWN file-scope pointers — `btl4App` (set to `new_app`
|
||||
at btl4main.cpp:631) and the global `hWnd` (the real main window). Those live in `btl4main.obj`
|
||||
and are the actual assigned pointers, so the resolvers are always correct regardless of the
|
||||
duplicate-symbol binding. `BlitSurface` and the placement code call the resolvers, never the
|
||||
`application`/`ghWnd` globals. New durable gotcha: `context/reconstruction-gotchas.md` §6
|
||||
duplicate-GLOBAL corollary.
|
||||
|
||||
Verified after the fix (`BT_GLASS_LOG`): `[glass] 'Heat MFD' port=Heat mask=0x4000 pal=3
|
||||
enable=2 ow=640 oh=480 nonzero=22227/307200`, `[glass] 'Secondary / Radar' port=sec mask=0x3f
|
||||
pal=1 enable=3 ow=480 oh=640 nonzero=26206/307200` — surfaces resolve and carry live pixels.
|
||||
`BT_GLASS_LOG` left in as a permanent per-surface resolve/pixel diagnostic (throttled).
|
||||
|
||||
Reference in New Issue
Block a user