Files
BT411/game/reconstructed/btl4grnd.hpp
T
arcattackandClaude Fable 5 6bb03aed0b Gitea #48 ROOT-CAUSED + FIXED: MFD "stray blocks / misplaced lamps" = uninitialized translation-table entries leaking pixels into other displays' bit-planes
The conviction was empirical, not theoretical: a new write-site trap
(BT_PLANE_AUDIT) in the seven L4VB16 drawing primitives logs any draw whose
color carries bits outside its port's plane mask -- the exact cross-display
corruption condition (Replace ORs an unmasked color; Or/Xor ignore the mask
entirely; And clears foreign planes).  A quiet solo session produced 15-30
leaks per minute:

    [plane] PORT 'sec' pixmap draw at(0,0) idx 217 entry=0xffffff00 mask=0x3f
    [plane] LEAK DrawPixelMap8[table] at(639,0) color=0xffffff00 mask=0x3f leak=0xff00

THE DEFECT: L4GraphicsPort::translationTable[256] is never initialized in the
ctor, and BuildSecondaryTranslation fills only the entries its BitWrangler
reaches -- 2^numberOfBits: 64 for the sec plane (mask 0x3F), 4 for the overlay
(0xC0).  Entries above that stay heap garbage.  Every draw resolves color
through this table, and the PIXMAP path indexes it with raw pixel values
0..255: the 480x640 radar background carries pixel index 217, whose garbage
entry's high bits (0xFF00 = ALL EIGHT MFD planes) were stamped into the shared
640x480 buffer -- invisible on the culprit page (the in-plane bits happened
dark) and visible as bright fragments at the same coordinates on every OTHER
display.  That is the operator's screenshot exactly: the same-position blips
on Mfd1+Mfd2 and the Heat-display block.

FIX (engine, both layers):
  * zero translationTable in the L4GraphicsPort ctor (plane-neutral default);
  * BuildSecondaryTranslation now cycles the in-plane pattern across entries
    [2^bits..255] -- high-index art degrades to its (index mod 2^bits) colour
    IN-PLANE and can never leak.  The 1995 binary ships the SAME 64-entry fill
    and survived on 6-bit art discipline; garbage is not a preservable
    behaviour, so the cycle-fill is a guarded PORT deviation (documented).

A/B PROOF: same probe, 60s -- 0 leaks after the fix (15-30/min before).
sim3 3-pod regression: zero crashes.

SECOND real defect found + fixed en route: sessions configure the CAMERA seat
first ("cameraInit" -- which includes the MISSION-REVIEW context:
configure(0, sec, 0, 0x00FF, native, rgb, mrpal.pcc), a DirectColor context
whose translation tables legitimately hold full RGB565 values spanning all 16
plane bits), and the viewpoint swap to the mech re-configured WITHOUT tearing
that tree down (btl4app's s_gaugeTreeBuilt latch treats the mech build as the
first).  The orphaned review gauges kept executing through stale DirectColor
ports.  BTL4GaugeRenderer::ConfigureForModel now overrides (ConfigureForModel
made virtual in L4GREND.h) and tears the prior entity-bound tree down before
every rebuild -- safe on first build, and the review screen rebuilds the same
way when the seat returns to the camera.

Also logged (open-questions): the review-screen PlayerStatus panels read the
compiled player at RAW BINARY OFFSETS (+0x1FC vehicle / +0x1C8 score /
+0x1C4 alive-dead box) -- the databinding trap, dormant until the review
screen runs; bridge before enabling the review.

Ruled out along the way (with evidence): the pilot-list label/erase geometry
(erase box 128x32 covers the 64x16 name rasters), the radar name labels
(view-level ClipImage clips them), PlayerStatus in-game execution ([ps] probe:
never runs in-game), and the PNAME bitmap dimensions (egg generator emits
64x16 exactly).

Why it "started with the comms feature" (#43): that wave registered the new
gauge classes with the config interpreter, letting more of the authored page
furniture parse and draw than before -- the leaking high-index pixmaps rode in
with it.  [T3 correlation detail; the leak + fix are T2 live-verified.]

Diagnostics kept (env-gated): BT_PLANE_AUDIT (the leak trap, now a permanent
regression tripwire), BT_PS_LOG, the port-level pixmap identity trap.

KB: gauges-hud.md (#48 section), decomp-reference.md (BT_PLANE_AUDIT),
open-questions.md (PlayerStatus databinding entry).  checkctx CLEAN.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 17:20:19 -05:00

94 lines
4.0 KiB
C++

//===========================================================================//
// File: btl4grnd.hpp //
// Project: BattleTech Brick: Gauge Renderer Manager //
// Contents: //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 02/13/95 CPB Initial coding. //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc. All rights reserved //
// PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
//
// SURVIVING HEADER (ground truth -- reproduced verbatim from
// 410SRC/.../BT_L4/BTL4GRND.HPP). Only the File:/Brick: banner above was
// corrected from the original (which carried a stale "rpl4grnd.hh" copy of
// the Red Planet sibling's comment). The class declaration is unchanged.
//
// Implementation reconstructed in btl4grnd.cpp from the shipped binary:
// BTL4GaugeRenderer ctor @004cbea0 (vtable 0051cebc)
// ~BTL4GaugeRenderer @004cbf40 (vtable slot 0)
// TestInstance @004cbf90
// NotifyOfNewInterestingEntity @004cbfa0 (vtable slot 9)
// NotifyOfBecomingUninterestingEntity @004cc028 (vtable slot 10)
//
#if !defined(BTL4GRND_HPP)
# define BTL4GRND_HPP
# if !defined(L4GREND_HPP)
# include <l4grend.hpp>
# endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~ BTL4GaugeRenderer ~~~~~~~~~~~~~~~~~~~~~~~~~~
class BTL4GaugeRenderer:
public L4GaugeRenderer
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
BTL4GaugeRenderer();
~BTL4GaugeRenderer();
Logical
TestInstance() const;
void
NotifyOfNewInterestingEntity(Entity *entity);
void
NotifyOfBecomingUninterestingEntity(Entity *entity);
//
// PORT FIX (Gitea #12 -- NOT in the surviving 1995 header): tear the
// built gauge tree down when the viewpoint mech is RE-STREAMED
// in-session (pre-launch host drop/rejoin re-creates every mech; the
// lobby-built tree's attribute pointers dangle and each widget is
// permanently DISABLED by the BT_DEV_GAUGES SEH guard, GAUGE.cpp:618).
// Performs the entity-bound half of the engine's mission-transition
// teardown (GaugeRenderer::ShutdownImplementation, GAUGREND.cpp:3264):
// alarms + all gauges + the entity grids. Warehouse / graphics ports /
// interpreter / controls lamps stay -- entity-independent, reused by
// the immediate ConfigureForModel rebuild. Called from
// BTL4Application::MakeViewpointEntity before ConfigureForModel;
// a no-op on the first (lobby) build.
//
void
TearDownForViewpointRestream();
// Gitea #48 (THE MFD-ARTIFACT ROOT CAUSE): tear the previous
// configuration's gauge tree down on EVERY viewpoint configure, then
// build. The camera seat configures first (`cameraInit` -- which
// includes the MISSION-REVIEW ports: `configure(0, sec, 0, 0x00FF,
// native, rgb, mrpal.pcc)` -- a DirectColor context whose translation
// tables hold full RGB565 values spanning ALL 16 plane bits); the swap
// to the mech re-configures WITHOUT tearing that tree down (the
// btl4app latch treats the mech build as "first"), so the review
// gauges kept executing through their orphaned DirectColor ports and
// every draw stamped pixels into EVERY display's plane -- the "stray
// blocks / misplaced lamps" on Heat/Mfd/sec. Convicted live by the
// BT_PLANE_AUDIT write trap: pixmap draws with mask 0x3F/0xC0 leaking
// 0xFF00/0x3F at the review furniture positions.
virtual void
ConfigureForModel(const char *configuration_name, Entity *entity);
};
#endif