gauges: reconstruct + register the first BT gauge widget (cmHeat) [widget recon 1]

Begins the BT gauge WIDGET reconstruction -- making the cockpit instruments show
live data instead of just frame art. The BT gauge method table
(BTL4MethodDescription[]) was a chain-only stub with zero registered
methodDescriptions, so every BT-specific gauge keyword was parse-skipped.

Registers the first widget, cmHeat (ColorMapperHeat -- tints the heat/critical
schematic palette by a named subsystem's live temperature):
- Added ColorMapperHeat::methodDescription (keyword "cmHeat", param list
  R,Md,C,St,St,St matching the binary .data) and registered it in
  BTL4MethodDescription[] (chain link stays last).
- Rewired ColorMapperHeat::Make to read methodDescription.parameterList[]
  (the interpreter restores each instance's parsed params there) instead of the
  earlier unrecovered DAT_* placeholders -- so it uses the real CFG rate/mode/
  colour-slot/palette/subsystem-name, and the runtime port arg as the graphics
  port.

Registering it exposed the /FORCE trap: two REAL functions in the chain were
undefined (silently stubbed -> would AV once the gauge builds). Reconstructed
both from the decomp:
- ColorMapper::BecameActive (@004c395c): invalidate the cached colour index +
  last-written RGB so the next Execute re-pushes the hardware palette.
- ColorMapperHeat::~ColorMapperHeat: empty -- the base chain (~ColorMapper ->
  ~Gauge) releases the HeatConnection + palettes.

Verified: register->parse->Make->ctor->FindSubsystem("GeneratorA") (resolves,
no "does not exist")->HeatConnection->Execute->palette-push runs end-to-end
under BT_DEV_GAUGES; no parse desync; combat un-regressed (TARGET DESTROYED,
0 crashes). Establishes the registration recipe + the /FORCE-check discipline
for every remaining widget. Details + priority order: docs/GAUGE_COMPOSITE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-06 15:05:47 -05:00
co-authored by Claude Opus 4.8
parent b526e92cad
commit 547f25e043
4 changed files with 117 additions and 18 deletions
+44
View File
@@ -220,3 +220,47 @@ yet reconstructed (parse-skipped). The separate window is now the **live viewer*
monitors. NOT a CFG rename (the CFG uses BT names pervasively + `MUNGA_L4` is shared with RP's aux names).
- **Polish:** overlay-plane compositing over `sec`; a pod-accurate RGB-packing toggle; texture atlas
(one lock/upload); device-reset recreate hardening for the additional swap chain.
## Widget reconstruction — the real fix (in progress; mapped by `bt-gauge-widget-recon-map`)
**Why the surfaces show only frames:** the BT gauge method table `BTL4MethodDescription[]` (btl4grnd.cpp)
was a chain-only STUB, and **no BT gauge class registered a `methodDescription`**, so every BT-specific gauge
keyword (`cmHeat`/`headingPointer`/`map`/`vertBar`/`GeneratorCluster`/…) failed table lookup and was
parse-skipped. The binary's real table @0x51c910 has 23 gauge entries; 19 keywords are actually invoked by
this CFG. The reconstructed classes exist in `btl4gaug/gau2/gau3.cpp` but most have prose-only (undefined)
ctors/Execute/connection-feeds — only a few chains are fully real code.
**The registration recipe (per widget, mirrors the engine — `NumericDisplayScalar`, L4GAUGE.cpp:542):**
1. Add `static MethodDescription methodDescription;` to the class in its `.hpp`.
2. Define `<Class>::methodDescription = { "cfgKeyword", <Class>::Make, { {type,NULL}…, PARAMETER_DESCRIPTION_END } }`
in the class's `.cpp`. **The param-type list MUST match the binary's `.data` exactly** — the parser reads
one token per entry to the `typeEmpty` terminator (GAUGREND.cpp:1458); a wrong count desyncs the parse.
3. Rewire `Make` to read `methodDescription.parameterList[]` (the interpreter restores each instance's parsed
params there before calling Make) instead of placeholder statics; the runtime port arg (`display_port_index`)
is the graphics port, NOT a param slot.
4. Register `&<Class>::methodDescription` in `BTL4MethodDescription[]` (btl4grnd.cpp), **chain link LAST**.
**⚠ THE /FORCE TRAP (the load-bearing gotcha): register a widget ONLY when its whole Make→ctor→feed→every-
vtable-slot chain is REAL code.** A registered class instantiates its vtable; any prose-only/undefined virtual
(dtor, `BecameActive`, a connection ctor) is `/FORCE`-stubbed to the image base and AVs the moment it's called.
The build "succeeds" (exit 0) and lies — **grep the link log for `unresolved external` on the class's symbols**
(filter out the known dead `mech3.obj` `DefaultData`/`CreateStreamedSubsystem` offline-factory externals).
**✅ Increment 1 — `cmHeat` (ColorMapperHeat) DONE (commit pending).** The first registered BT gauge widget.
Pure wiring proved the whole pipeline: added the `methodDescription` (`R,Md,C,St,St,St`, keyword `cmHeat`),
rewired `Make` to `parameterList[]`, registered it. Registering it EXPOSED two `/FORCE`-stubbed real functions
in the chain (the map had missed them) — reconstructed both from the decomp: `ColorMapper::BecameActive`
(@004c395c — invalidates the cached colour index + last RGB so the next Execute re-pushes the palette) and
`ColorMapperHeat::~ColorMapperHeat` (empty — base chain releases the HeatConnection + palettes). Verified:
register→parse→Make→ctor→`FindSubsystem("GeneratorA")` (resolves — no "does not exist")→HeatConnection→
Execute→palette-push runs end-to-end; combat un-regressed (TARGET DESTROYED, 0 crashes); the sec/heat
schematic zones are now tinted by the REAL subsystem `currentTemperature` (stable tint since temp is stable —
the visible-animation win is `headingPointer` next). **Method established for every remaining widget.**
**Next increments (priority order from the map):** `headingPointer` (rotating compass + numeric heading —
reconstruct from prose `btl4gaug.cpp:644`, reads owner quaternion directly, no attribute table/connection
needed — the visible money-shot); then `cmArmor`/`colorMapperMultiArmor` (armor schematic, needs the
`ArmorZoneConnection`/`MultiArmorConnection` classes reconstructed); then the attribute-table wave (`vertBar`/
`segmentArcRatio` speed/`GeneratorCluster` — need `AttributePointers[]` on Mech/HeatableSubsystem, a separate
pass); the XL items (`map`/`vehicleSubSystems`/`PlayerStatus`) last. The POD path needs the FULL 23-entry
table with real ctors (the dev tolerant-skip is the on-ramp, not the finish).