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>
Glass Cockpit — the desktop developer layer (BT_GLASS / BT_STEAM)
living
plan 2026-07-17; CMakeLists.txt gates; BT412 prior art (reference only)
pod-hardware
build-and-run
multiplayer
gauges-hud
PadRIO
miniconsole
glass-cockpit
Glass Cockpit — the desktop developer layer
Purpose: developer tooling so game developers can test their work WITHOUT booting a Tesla II
pod — and stay far enough out of the game that nothing a real pod requires can break. NOT a
consumer product (GDI-grade UI is the ceiling). Pod fidelity outranks desktop convenience in
every trade-off.
The compile gates (the ONLY compile-time feature gates in the tree)
Gate
Default
Adds
BT_GLASS
OFF
PadRIO input (XInput+keyboard), per-display cockpit windows (or the legacy single button panel), desktop plasma window, glass platform preset, miniconsole mission launcher
BT_STEAM
OFF (requires BT_GLASS)
Steam transport (ISteamNetworkingSockets) + ISteamMatchmaking lobby
A no-flags configure is the pure pod game — the build of record. cmake options are
cached, so a developer configures a build/ with -DBT_GLASS=ON once.
Convention:BT_GLASS/BT_STEAM are compile gates; every other BT_* name is a RUNTIME
env gate (BTEnvOn) — do not add compile gates without updating this file.
No weak-linkage/optional symbols — /FORCE turns unresolved externals into runtime AVs
(reconstruction-gotchas); gated calls must be structurally present-or-absent at compile time.
Plan of record (2026-07-17)
Working branch glass-cockpit (from master e2c21c4). Steps: (1) gates+scaffolding [THIS],
(2) PadRIO glass cockpit, (3) miniconsole self-launch, (4) Steam transport+lobby. Full plan:
the approved plan file; running detail: docs/GLASS_COCKPIT.md. The retired BT412 trees
(C:\VWE\BT412; local branch local-abandoned-20260717) are read-only reference — no code is
copied from them.
Step 2a (.CTL id audit): DONE 2026-07-17 [T2]. The streamed .CTL positional ids landed
every MechControlsMapper record ONE MEMBER LATE (our chain starts at 2, the binary's at 3)
— a latent REAL-POD bug (RIO throttle would drive pedalsPosition), masked on dev boxes by the
keyboard bridge. Fixed ungated: ids pinned to binary numbering + id-2 pad + static_assert
locks (mechmppr.hpp/.cpp); torso/weapon chains were already aligned. Permanent env-gated
diagnostic: BT_CTRLMAP_LOG=1 dumps every streamed record's resolved member offset
(L4CTRL.cpp CreateStreamedMappings). Full evidence: docs/GLASS_COCKPIT.md §2a.
Step 2 (PadRIO glass cockpit): DONE 2026-07-17 [T2].RIOBase seam (L4RIO.h,
unconditional) + gated L4CONTROLS=PAD → PadRIO (L4PADRIO.* XInput+keyboard,
L4PADBINDINGS.*content\bindings.txt); bridge stand-downs auto-yield to a live device
(BTRIODevicePresent, BT_KEY_BRIDGE unset=auto/0=off/1=on); on-screen panel L4PADPANEL.*
follows vRIO (C:\VWE\vrio CockpitLayout/PanelCanvas — 104 controls incl. the two hex
keypads → real KeyEvents; right-click latch); desktop plasma L4PLASMAWIN.*
(L4PLASMA=SCREEN, buffer is top-down); -platform glass preset + run.cmd token. Secondary
displays reuse the EXISTING dev-gauge modes (dock / BT_DEV_GAUGES_WINDOW=1 window /
_DOCK=1 overlay — gauges-hud); no new MFD code, no L4VB16.cpp exposure.
Button-trap guard: base ConfigureMappableMessageHandler no longer abort()s by default
(BT_BUTTON_TRAP=1 restores) — each [FAIL] log = a missing L4 override to reconstruct.
Verified: authentic-path input (engine push → streamed .CTL → mapper), panel-click
survival, 2-node loopback MP un-regressed on the pod build. Detail: docs/GLASS_COCKPIT.md.
Step 3 (miniconsole): DONE 2026-07-17 [T2].game/glass/btl4fe.* (menu + console-shape
egg writer, golden-tested vs MP.EGG) + btl4console.* (the marshal: a worker-thread console
CLIENT speaking the btconsole.py wire verbatim; content\marshal.log). ZERO engine hooks —
the engine runs the stock console ladder. Per-mission process relaunch; BT_FE_* env arms the
marshal (menu relaunches clear it). Verified: solo cycle (menu→mission→60s clock→stop→menu)
and menu-hosted 2-node LAN.
Step 4 (Steam): CODE COMPLETE 2026-07-18 [T2 single-machine]. See steam-networking —
the wire seam + L4STEAMNET identity-token transport + btl4lobby. Live 2-account
cross-machine session pending (docs/STEAM_TEST.md).
Input-coverage audit + keyboard reconciliation: DONE 2026-07-20 [T2]. Root cause of the
dead panel: MechRIOMapper's message ids were chained one enum too high (0x19-0x2a) — the
binary RIO table @0051dd30 re-registers the BASE aux/zoom ids 3..0x13 (Hotbox 0x1a); fixed
ungated + static_assert-locked (btl4mppr.hpp) → all 24 MFD-bank + 2 zoom buttons live
(52/72 panel buttons now work; 8 dead await handler reconstruction — Gitea backlog issue;
12 have no streamed mapping authored, authentically inert). Keyboard = the ~20 core
gameplay actions on the CONTROLS.MAP keys; the PANEL covers every pod address by click
(right-click = hold latch) — the merged default profile lives in L4PADBINDINGS.cpp
(auto-writes content\bindings.txt; W/S/A/D/Q/E/R/F/X drive, 1-4/Space/Ctrl fire, M/N/H/C =
pod buttons 0x18/0x15/0x2C/0x2F, /V view toggle + J/K/L preset cycles hardcoded in PadRIO). Bound keys are SUPPRESSED from the typed 1995 channel (PadRIO::SuppressKey, the btinput pattern — ended the glass double-dispatch: 'w'=pilot-select, numpad/F-key key-up aliases); unbound keys keep their authentic meanings (5/z presets, t-o pilot select, +/- zoom). In BAS control mode the pod turns with the STICK (Q/E) and pedals are inactive — authentic; A/D turn in MID/ADV. Full audit + census: docs/GLASS_COCKPIT.md` §2026-07-20.
Per-display cockpit windows (BT_GLASS_PANELS): DONE 2026-07-20 [T2 startup-verified].
The -platform glass preset now breaks the secondary displays out of the single combined
panel/strip into ONE desktop window PER pod display, each carrying that display's surface
WITH its RIO button bank placed around it, arranged pod-faithfully around the main view
(engine/MUNGA_L4/L4GLASSWIN.*, new TU). Windows: Heat (UL) / Mfd2 (UC) / Comm (UR) /
Mfd1 (LL) / Mfd3 (LR) each with 8 RED MFD buttons split 4 above / 4 below the surface;
Secondary/Radar (portrait sec) with the 12 YELLOW Secondary buttons split left/right;
a Flight Controls window for the no-display banks (throttle 0x38-3F, joystick/fire
0x40-47, panic). Each window is a GDI window (like gauges-hud's pad panel + the plasma
window) — the surface is CPU-expanded from the shared gauge buffer
(SVGA16::ExpandPlaneToBGRA, no D3D) and StretchDIBits'd in, so the whole D3D
dev-composite path (dock / separate window / overlay) stands down while these are up
(BTDrawGaugeInset/BTGaugeWindowRenderAndPresent early-return; no gBTGaugeDockBottom
strip). Runtime gate BT_GLASS_PANELS (default ON under -platform glass, =0 falls
back to the single pad panel + docked gauges) — read by L4PADRIO (which panel to create),
L4VB16 (suppress compositing), and btl4main (skip the world-window dock strip). The
display↔bank map (spine of the feature): Heat 0x28-2F, Mfd2 0x20-27, Comm 0x30-37,
Mfd1 0x08-0F, Mfd3 0x00-07, sec 0x10-1B (pod-hardware §Bank→MFD). Verified: build +
bounded glass launch — [glasswin] per-display cockpit up (7 windows…), no crash, full
mission loop un-regressed; surfaces carry LIVE gauge content (BT_GLASS_LOG = per-surface
resolve/pixel diagnostic). Layout constants (surface sizes, exact button sub-positions,
yellow left/right split) are marked tunable in L4GLASSWIN.cpp. Detail: docs/GLASS_COCKPIT.md.
⚠ Bug found + fixed during bring-up: surfaces were blank because application/ghWnd are
duplicate-defined globals that bind non-deterministically under /FORCE — the fresh
L4GLASSWIN TU read application == NULL → gauge renderer NULL. Fix: reach the
renderer/window via BTResolveGaugeRenderer()/BTResolveMainWindow(), DEFINED in
game/btl4main.cpp off its real btl4App/hWnd pointers (never the globals directly). See
reconstruction-gotchas §6 duplicate-GLOBAL corollary.