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>
156 lines
3.7 KiB
C++
156 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include "..\munga\gaugrend.h"
|
|
#include "l4vb16.h"
|
|
#include "l4plasma.h"
|
|
#include "l4gauima.h"
|
|
#include "l4wrhous.h"
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ L4GaugeRenderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class L4GaugeRenderer:
|
|
public GaugeRenderer
|
|
{
|
|
public:
|
|
|
|
//--------------------------------------------------------------------
|
|
// Construction, Destruction, Testing
|
|
//--------------------------------------------------------------------
|
|
L4GaugeRenderer(bool windowed, int *secondaryIndex, int *aux1Gauge, int *aux2Gauge);
|
|
~L4GaugeRenderer();
|
|
|
|
void
|
|
LocalEmergencyShutdown();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
//--------------------------------------------------------------------
|
|
// Profiling support
|
|
//--------------------------------------------------------------------
|
|
protected:
|
|
Scalar
|
|
GetCurrentFramePercentage();
|
|
//--------------------------------------------------------------------
|
|
// GraphicsPort methods
|
|
//--------------------------------------------------------------------
|
|
public:
|
|
void
|
|
BuildGraphicsPort(
|
|
int port_number,
|
|
const char *name,
|
|
int rotation,
|
|
int bitAllocation,
|
|
SVGA16::PaletteID palette_ID,
|
|
L4GraphicsPort::ChannelEnableID enable_ID,
|
|
Palette8 *palette
|
|
);
|
|
|
|
void
|
|
RemapGraphicsPort(
|
|
int port_number,
|
|
SVGA16::PaletteID palette_ID,
|
|
L4GraphicsPort::ChannelEnableID enable_ID,
|
|
Palette8 *palette
|
|
);
|
|
|
|
void
|
|
BuildExternalGraphicsPort(
|
|
int port_number,
|
|
const char *name,
|
|
int bitAllocation
|
|
);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// 'palette ramping'
|
|
//--------------------------------------------------------------------
|
|
//
|
|
void
|
|
FadeToWhite(Scalar number_of_seconds);
|
|
void
|
|
FadeToNormal(Scalar number_of_seconds);
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Accessors
|
|
//--------------------------------------------------------------------
|
|
//
|
|
GraphicsDisplay
|
|
*GetExternalDisplay()
|
|
{
|
|
Check(this);
|
|
return externalDisplay;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Configuration
|
|
//--------------------------------------------------------------------
|
|
//
|
|
// VIRTUAL (Gitea #48): BTL4GaugeRenderer overrides this to tear the
|
|
// previous viewpoint's gauge tree down before rebuilding -- the camera
|
|
// seat's cameraInit (the MISSION-REVIEW ports/gauges, DirectColor over
|
|
// sec+overlay) otherwise survives the swap to the mech and its per-frame
|
|
// draws stamp full-16-bit pixels across EVERY display plane.
|
|
virtual void
|
|
ConfigureForModel(
|
|
const char *configuration_name,
|
|
Entity *entity
|
|
);
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// ExecuteImplementation
|
|
//--------------------------------------------------------------------
|
|
//
|
|
protected:
|
|
void
|
|
ExecuteForeground();
|
|
Logical
|
|
ExecuteBackgroundDisplayUpdate();
|
|
void
|
|
LoadMissionImplementation(
|
|
Mission *mission
|
|
);
|
|
virtual void
|
|
NotifyOfNewInterestingEntity(Entity *entity);
|
|
virtual void
|
|
NotifyOfBecomingUninterestingEntity(Entity *entity);
|
|
void
|
|
ShutdownImplementation();
|
|
void
|
|
SuspendImplementation();
|
|
void
|
|
ResumeImplementation();
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Video effects
|
|
//--------------------------------------------------------------------
|
|
//
|
|
public:
|
|
void
|
|
SpecialEffect(VideoEffectType type, Scalar duration);
|
|
|
|
protected:
|
|
|
|
void
|
|
ProcessVideoEffects();
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Protected data
|
|
//--------------------------------------------------------------------
|
|
//
|
|
protected:
|
|
Logical
|
|
palettesAreActive;
|
|
|
|
GraphicsDisplay
|
|
*graphicsDisplay,
|
|
*externalDisplay;
|
|
|
|
Logical
|
|
scrambleVideoFlag;
|
|
Time
|
|
scrambleVideoTimeout;
|
|
};
|