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>
441 lines
19 KiB
C++
441 lines
19 KiB
C++
//===========================================================================//
|
|
// File: btl4grnd.cpp //
|
|
// Project: BattleTech Brick: Gauge Renderer Manager //
|
|
// Contents: BTL4GaugeRenderer -- the BattleTech L4 (cockpit) gauge renderer //
|
|
// manager. Owns the gauge warehouse + lamp manager, builds the //
|
|
// gauge configuration from gauge\l4gauge.cfg, and routes //
|
|
// interesting/uninteresting world entities into the moving/static //
|
|
// draw lists. //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 02/13/95 CPB Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994, Virtual World Entertainment, Inc. All rights reserved //
|
|
// PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTED from the shipped binary. Behaviour follows the Ghidra
|
|
// pseudo-C in the bt_l4 cluster (part_014.c); class/member/method names are
|
|
// taken from the surviving BTL4GRND.HPP and from the direct Red Planet
|
|
// analogue RP_L4/RPL4GRND.cpp (RPL4GaugeRenderer). Each method cites the
|
|
// originating @ADDR.
|
|
//
|
|
// NOTE ON THE FILE NAME: despite the "...GRND" name, this brick is the
|
|
// *gauge* renderer manager (HUD/cockpit), NOT a 3D ground/world renderer.
|
|
// The surviving header comment even calls the brick "Gauge Renderer
|
|
// Manager", and the only class it declares is BTL4GaugeRenderer. The
|
|
// out-the-window 3D world view is assembled by BTL4VID (btl4vid.cpp,
|
|
// @004cdac0..) -- a separate translation unit.
|
|
//
|
|
// Helper-function name mapping (engine internals referenced by the decomp):
|
|
// FUN_0046f97c L4GaugeRenderer base constructor
|
|
// FUN_0046fbcc L4GaugeRenderer::~L4GaugeRenderer (chain)
|
|
// FUN_0046fd6c L4GaugeRenderer::NotifyOfNewInterestingEntity
|
|
// FUN_0046fda0 L4GaugeRenderer::NotifyOfBecomingUninterestingEntity
|
|
// FUN_00447b60 GaugeRenderer::TestInstance
|
|
// FUN_00447fc0 GaugeRenderer::Remove(0) (purge all gauges)
|
|
// FUN_00448928 GaugeRenderer::BuildConfigurationFile(cfg, methods)
|
|
// FUN_00407064 ResourceFile::SearchList(resourceID, type)
|
|
// FUN_0041a1a4 Object::IsDerivedFrom(ClassDerivations&)
|
|
// FUN_004434f4 movingEntities.Add(entity) (this+0x94)
|
|
// FUN_00443510 movingEntities.Remove(entity)
|
|
// FUN_00443864 staticEntities.Add(entity) (this+0xb0)
|
|
// FUN_00443930 staticEntities.Remove(entity)
|
|
// FUN_00448c54 L4LampManager base constructor
|
|
// FUN_00468778 L4Warehouse constructor
|
|
// FUN_00474c4c (controls/secondary-palette helper ctor, app-derived)
|
|
// FUN_004022d0 operator delete / Unregister+free
|
|
// FUN_00402298 operator new
|
|
// DAT_004efc94 the global Application* (application)
|
|
//
|
|
// Inherited members used below live in L4GaugeRenderer / GaugeRenderer
|
|
// (l4grend.hpp / gaugrend.hpp), NOT in this subclass -- which is why the
|
|
// surviving header declares no data members:
|
|
// warehousePointer this[0x13] (@0x4c) -- L4Warehouse*
|
|
// lampManager this[0x7033] -- L4LampManager*
|
|
// movingEntities @0x94 -- list of Movers
|
|
// staticEntities @0xb0 -- list of Terrain
|
|
//
|
|
|
|
#include <bt.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(BTL4GRND_HPP)
|
|
# include <btl4grnd.hpp>
|
|
#endif
|
|
#if !defined(BTL4GAUG_HPP)
|
|
# include <btl4gaug.hpp> // the BT gauge classes (Compass, etc.)
|
|
# include <btl4gau2.hpp> // the composite cluster gauges + VehicleSubSystems
|
|
# include <btl4rdr.hpp> // MapDisplay (the "map" radar gauge)
|
|
# include <btl4gau3.hpp> // PlayerStatus (the comm/score gauge)
|
|
#endif
|
|
#if !defined(L4LAMP_HPP)
|
|
# include <l4lamp.hpp>
|
|
#endif
|
|
#include <GAUGALRM.hpp> // GaugeAlarmManager (TearDownForViewpointRestream, Gitea #12)
|
|
#include <btl4galm.hpp> // BTL4GaugeAlarmManager (the #47 override -- constructed in the ctor)
|
|
#if !defined(L4WARE_HPP)
|
|
# include <l4ware.hpp>
|
|
#endif
|
|
#if !defined(TERRAIN_HPP)
|
|
# include <terrain.hpp>
|
|
#endif
|
|
#if !defined(APP_HPP)
|
|
# include <app.hpp>
|
|
#endif
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
// BTL4MethodDescription list
|
|
//#############################################################################
|
|
//
|
|
// Passed to GaugeRenderer::BuildConfigurationFile() so the config-file
|
|
// interpreter can instantiate gauges by name. Mirrors RPL4MethodDescription
|
|
// in RPL4GRND.cpp (which lists &Compass::methodDescription,
|
|
// &ThreatIndicator::methodDescription, ...). The concrete BT gauge classes
|
|
// are defined in btl4gaug.cpp; the table itself is the .data block at
|
|
// 0051c910 and chains to the L4 base table.
|
|
//
|
|
// Recovered table entries (@0051c910, in order) -- MethodDescription* each;
|
|
// concrete gauge class names TODO (resolve against btl4gaug.cpp):
|
|
// 0x517ea4 0x51a2b0 0x5160ac 0x517614 0x5142b4 0x514b44
|
|
// 0x514f8c 0x5146fc 0x5153d4 0x51581c 0x515c64 0x5164f4
|
|
// 0x51693c 0x5171cc 0x5138f4 0x51a6f8 (one of the last two is the
|
|
// BTL4ChainToPrevious chain)
|
|
//
|
|
extern
|
|
MethodDescription
|
|
*L4MethodDescription[];
|
|
|
|
MethodDescription
|
|
BTL4ChainToPrevious = METHOD_DESCRIPTION_CHAIN(L4MethodDescription);
|
|
|
|
extern
|
|
MethodDescription
|
|
*BTL4MethodDescription[]; // defined in .data @0051c910
|
|
|
|
// TODO(bring-up): minimal reconstruction of the BT gauge method table. The
|
|
// real .data table @0051c910 listed the BT-specific gauge methodDescription
|
|
// entries (Compass/ThreatIndicator/... analogues, see RPL4MethodDescription);
|
|
// those gauge classes' methodDescription members are not all reconstructed yet,
|
|
// so for the first link this table contains only the chain-to-previous link,
|
|
// which routes config lines to the engine's base L4MethodDescription methods.
|
|
MethodDescription
|
|
*BTL4MethodDescription[] =
|
|
{
|
|
//
|
|
// BT gauge WIDGET reconstruction -- register each BT-specific gauge
|
|
// class's methodDescription so the config interpreter can build it
|
|
// (the CFG keyword -> class Make). Add ONE at a time, only when its
|
|
// whole Make->ctor->feed chain is REAL code (a prose-only/undefined
|
|
// link would be /FORCE-stubbed and AV at runtime; see CLAUDE.md §10).
|
|
// The chain-to-previous link MUST stay LAST (routes unmatched keywords
|
|
// to the engine base table L4MethodDescription).
|
|
//
|
|
&ColorMapperHeat::methodDescription, // "cmHeat" -- heat-driven palette tint
|
|
&HeadingPointer::methodDescription, // "headingPointer" -- compass needle + heading
|
|
&ColorMapperArmor::methodDescription, // "cmArmor" -- per-zone armor-damage tint
|
|
&ColorMapperMultiArmor::methodDescription, // "colorMapperMultiArmor" -- worst-of-8-zones tint
|
|
&ColorMapperCritical::methodDescription, // "cmCrit" -- subsystem-critical-state tint
|
|
&VertTwoPartBar::methodDescription, // "vertBar" -- vertical fill bar (coolant/heat)
|
|
&SegmentArcRatio::methodDescription, // "segmentArcRatio" -- segmented arc dial (speed)
|
|
&OneOfSeveralPixInt::methodDescription, // "oneOfSeveralPixInt" -- button-state lamp (duck/light/mode)
|
|
&MapDisplay::methodDescription, // "map" -- the radar / tactical display
|
|
&PlayerStatus::methodDescription, // "PlayerStatus" -- comm/score name-tag gauge
|
|
&VehicleSubSystems::methodDescription, // "vehicleSubSystems" -- engineering-screen subsystem cluster panels
|
|
&BitMapInverseWipe::methodDescription, // "LeakGauge" -- coolant-leak inverse-wipe (Condenser/CoolantMassLeakRate)
|
|
&VertNormalSlider::methodDescription, // "vertNormalSlider" -- condenser valve-setting slider (heat MFD)
|
|
&PilotList::methodDescription, // "pilotList" -- Comm KILLS/DEATHS pilot roster
|
|
&GeneratorCluster::methodDescription, // "GeneratorCluster" -- the 4 generator engineering panels (buttons 9-12)
|
|
&SectorDisplay::methodDescription, // "sectorDisplay" -- radar SECTOR X/Z read-out (Secondary overlay)
|
|
&PrepEngrScreen::methodDescription, // "prepEngr" -- per-Eng-screen static label overlay (12x)
|
|
&MessageBoard::methodDescription, // "messageBoard" -- sec-MFD comm/status ticker (DEFERRED source -> empty)
|
|
&BTL4ChainToPrevious
|
|
};
|
|
|
|
|
|
//
|
|
//#############################################################################
|
|
// BTL4GaugeRenderer
|
|
//#############################################################################
|
|
//
|
|
// @004cbea0 (vtable 0051cebc)
|
|
//
|
|
// Parallels RPL4GaugeRenderer::RPL4GaugeRenderer: chain to the L4 base, build
|
|
// the lamp manager and gauge warehouse, then drive BuildConfigurationFile
|
|
// over gauge\l4gauge.cfg using the BTL4MethodDescription table.
|
|
//
|
|
BTL4GaugeRenderer::BTL4GaugeRenderer()
|
|
:
|
|
//------------------------------------------------------------------
|
|
// In the shipped BT binary the base ctor (FUN_0046f97c) was called
|
|
// with `this` only -- the original L4GaugeRenderer took no arguments
|
|
// and BT never drove the secondary-palette flashing path (unlike RP,
|
|
// which calls SVGA16::FlashPalette in its ctor). The modernized
|
|
// WinTesla engine grew the signature
|
|
// L4GaugeRenderer(bool windowed, int*, int*, int*)
|
|
// to support windowed/secondary-palette modes. The pod runs
|
|
// fullscreen and BT supplies no secondary/aux gauge indices, so the
|
|
// faithful translation passes windowed=false and null index pointers.
|
|
//------------------------------------------------------------------
|
|
L4GaugeRenderer(false, NULL, NULL, NULL) // FUN_0046f97c (orig: no args)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
//----------------------------------------
|
|
// Create lamp manager
|
|
// alloc 0x14; L4LampManager() @004c8c54; the object is then given the
|
|
// BT-specific lamp-name/index vtable (0051ceb0) so config lines like
|
|
// "coolingLoop1" resolve to the right lamp -- see btl4gaug.cpp.
|
|
//
|
|
// The shipped binary built the lamp manager with no argument
|
|
// (FUN_00448c54(obj)); the WinTesla L4LampManager ctor now requires
|
|
// the LBE4ControlsManager, fetched from the application exactly as
|
|
// the RP analogue (RPL4GRND.cpp) does. The application[0x3c] slot
|
|
// the decomp reads to seed the secondary helper IS this controls
|
|
// manager (Application::GetControlsManager()).
|
|
//----------------------------------------
|
|
Check(application);
|
|
LBE4ControlsManager
|
|
*controls_manager = (LBE4ControlsManager *)
|
|
(application->GetControlsManager());
|
|
Check(controls_manager);
|
|
|
|
lampManager = new L4LampManager(controls_manager); // this[0x7033]
|
|
Register_Object(lampManager);
|
|
|
|
//----------------------------------------
|
|
// Gauge-alarm manager (Gitea #47): the BTL4 override whose
|
|
// Read/CreateGaugeAlarmStreamItem bodies live at @004cc2fc/@004cc294.
|
|
// The base GaugeRenderer ctor NULLs gaugeAlarmManager (GAUGREND.cpp:2841)
|
|
// and Activate/Deactivate Check() it -- without this, MechTech's
|
|
// Start/StopEntityAlarm delivery (the jam / bay-fire ENG-button flash)
|
|
// had no receiver.
|
|
//----------------------------------------
|
|
gaugeAlarmManager = new BTL4GaugeAlarmManager();
|
|
Register_Object(gaugeAlarmManager);
|
|
|
|
//----------------------------------------
|
|
// Secondary / controls helper bound to the application
|
|
// alloc 0x44; FUN_00474c4c(application[0x3c]). this[0x7032].
|
|
//----------------------------------------
|
|
// (BT-specific; see ctor @004cbea0)
|
|
|
|
//----------------------------------------
|
|
// Create warehouse
|
|
//----------------------------------------
|
|
warehousePointer = new L4Warehouse(); // alloc 0x74; FUN_00468778; this[0x13]
|
|
Register_Object(warehousePointer);
|
|
|
|
//----------------------------------------
|
|
// Initialize interpreter
|
|
//----------------------------------------
|
|
BuildConfigurationFile( // FUN_00448928
|
|
"gauge\\l4gauge.cfg", // @0051ce9e
|
|
BTL4MethodDescription
|
|
);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~BTL4GaugeRenderer
|
|
//#############################################################################
|
|
//
|
|
// @004cbf40 (vtable slot 0 -- scalar/vector deleting destructor)
|
|
//
|
|
BTL4GaugeRenderer::~BTL4GaugeRenderer()
|
|
{
|
|
Check(this);
|
|
|
|
//----------------------------------------
|
|
// Make sure all gauges removed BEFORE we
|
|
// destroy the warehouse!!
|
|
//----------------------------------------
|
|
Remove(0); // FUN_00447fc0(this, 0)
|
|
|
|
//----------------------------------------
|
|
// destroy warehouse
|
|
//----------------------------------------
|
|
Check(warehousePointer); // this[0x13]
|
|
Unregister_Object(warehousePointer);
|
|
delete warehousePointer; // (**warehousePointer)(warehousePointer, 3)
|
|
warehousePointer = NULL;
|
|
|
|
Check_Fpu();
|
|
// base ~L4GaugeRenderer (FUN_0046fbcc) runs on chain-out.
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
// @004cbf90
|
|
//
|
|
Logical
|
|
BTL4GaugeRenderer::TestInstance() const
|
|
{
|
|
return GaugeRenderer::TestInstance(); // FUN_00447b60
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// TearDownForViewpointRestream (PORT FIX -- Gitea #12)
|
|
//#############################################################################
|
|
//
|
|
// The in-session mech RE-STREAM (a pre-launch host drop/rejoin re-creates all
|
|
// mechs at mission launch) frees the mech the LOBBY-built gauge tree was bound
|
|
// to; every gauge Execute then AVs on its dangling attribute pointers and the
|
|
// BT_DEV_GAUGES SEH guard (Gauge::GuardedExecute, GAUGE.cpp:618) disables each
|
|
// one PERMANENTLY (rate=0, nothing rebinds) -- the frozen dev-gauges window of
|
|
// incident #12. The AUTHENTIC engine flow only tears the tree down at mission
|
|
// transitions (Application::Shutdown -> gaugeRenderer->Shutdown() ->
|
|
// ShutdownImplementation -> Remove(0), APP.cpp:787 / GAUGREND.cpp:3264); the
|
|
// re-stream path bypasses it. This method performs the ENTITY-BOUND half of
|
|
// that same ShutdownImplementation sequence, in the same order:
|
|
// gaugeAlarmManager->RemoveAllAlarms() (alarms hold entity/subsystem ptrs)
|
|
// Remove(0) (delete every gauge, active+inactive)
|
|
// movingEntities/staticEntities.Clear() (raw Entity* grids for radar/map)
|
|
// and deliberately SKIPS the mission-scoped steps -- warehouse purge, graphics
|
|
// port destruction, lampManager->RemoveAllLamps() (the L4Lamps are owned by the
|
|
// CONTROLS layer, which registers &lamp->automaticValue into its buttonGroup --
|
|
// deleting them mid-session would dangle the button mappings; the mech-state
|
|
// "lamps" like AnimatedSubsystemLamp are Gauges and go with Remove(0)). The
|
|
// caller (MakeViewpointEntity) immediately re-runs ConfigureForModel("Init",
|
|
// <new mech>) against the still-initialized interpreter/warehouse, so the tree
|
|
// rebuilds bound to the NEW mech -- the gauge renderer builds lazily by design.
|
|
//
|
|
void
|
|
BTL4GaugeRenderer::TearDownForViewpointRestream()
|
|
{
|
|
Check(this);
|
|
|
|
if (gaugeAlarmManager != NULL)
|
|
{
|
|
Check(gaugeAlarmManager);
|
|
gaugeAlarmManager->RemoveAllAlarms();
|
|
}
|
|
Remove(0); // FUN_00447fc0(this, 0) -- all gauges
|
|
movingEntities.Clear();
|
|
staticEntities.Clear();
|
|
Check_Fpu();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// NotifyOfNewInterestingEntity
|
|
//#############################################################################
|
|
//
|
|
// @004cbfa0 (vtable slot 9)
|
|
//
|
|
void
|
|
BTL4GaugeRenderer::NotifyOfNewInterestingEntity(Entity *entity)
|
|
{
|
|
Check(this);
|
|
Check(entity);
|
|
|
|
//------------------------------------------------------
|
|
// If the entity has no gauge representation, discard it
|
|
//------------------------------------------------------
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
|
|
ResourceDescription
|
|
*resource_description =
|
|
application->GetResourceFile()->SearchList( // FUN_00407064
|
|
entity->GetResourceID(), // entity[0x1bc]
|
|
ResourceDescription::GaugeImageStreamResourceType // 0x12
|
|
);
|
|
|
|
if (resource_description != NULL)
|
|
{
|
|
//
|
|
//---------------------------------------------------------
|
|
// Place object in either moving list or static array
|
|
//---------------------------------------------------------
|
|
//
|
|
if (entity->IsDerivedFrom(*Mover::GetClassDerivations())) // 0x4e4518
|
|
{
|
|
movingEntities.Add(entity); // FUN_004434f4, this+0x94
|
|
}
|
|
else if (entity->IsDerivedFrom(*Terrain::GetClassDerivations())) // 0x4e6ef8
|
|
{
|
|
staticEntities.Add(entity); // FUN_00443864, this+0xb0
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// Chain to "ancestor" method
|
|
//------------------------------------------------------
|
|
L4GaugeRenderer::NotifyOfNewInterestingEntity(entity); // FUN_0046fd6c
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// NotifyOfBecomingUninterestingEntity
|
|
//#############################################################################
|
|
//
|
|
// @004cc028 (vtable slot 10)
|
|
//
|
|
void
|
|
BTL4GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *entity)
|
|
{
|
|
Check(this);
|
|
Check(entity);
|
|
|
|
//------------------------------------------------------
|
|
// If the entity has no gauge representation, discard it
|
|
//------------------------------------------------------
|
|
Check(application);
|
|
Check(application->GetResourceFile());
|
|
|
|
ResourceDescription
|
|
*resource_description =
|
|
application->GetResourceFile()->SearchList( // FUN_00407064
|
|
entity->GetResourceID(),
|
|
ResourceDescription::GaugeImageStreamResourceType // 0x12
|
|
);
|
|
|
|
if (resource_description != NULL)
|
|
{
|
|
//---------------------------------------------------------
|
|
// Remove entity from either moving list or static array
|
|
//---------------------------------------------------------
|
|
if (entity->IsDerivedFrom(*Mover::GetClassDerivations())) // 0x4e4518
|
|
{
|
|
movingEntities.Remove(entity); // FUN_00443510, this+0x94
|
|
}
|
|
else if (entity->IsDerivedFrom(*Terrain::GetClassDerivations())) // 0x4e6ef8
|
|
{
|
|
staticEntities.Remove(entity); // FUN_00443930, this+0xb0
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------
|
|
// Chain to "ancestor" method
|
|
//------------------------------------------------------
|
|
L4GaugeRenderer::NotifyOfBecomingUninterestingEntity(entity); // FUN_0046fda0
|
|
}
|
|
|
|
//
|
|
// Gitea #48 -- the MFD-artifact root cause fix. See btl4grnd.hpp for the full
|
|
// conviction chain (cameraInit's mission-review DirectColor context surviving
|
|
// the viewpoint swap and stamping all 16 planes). Every configure now tears
|
|
// the prior entity-bound tree down first; safe on the first build (empty tree),
|
|
// and the review screen itself rebuilds the same way when the seat returns to
|
|
// the camera at round end.
|
|
//
|
|
void
|
|
BTL4GaugeRenderer::ConfigureForModel(
|
|
const char *configuration_name,
|
|
Entity *entity
|
|
)
|
|
{
|
|
TearDownForViewpointRestream();
|
|
L4GaugeRenderer::ConfigureForModel(configuration_name, entity);
|
|
}
|