//===========================================================================// // 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 #pragma hdrstop #if !defined(BTL4GRND_HPP) # include #endif #if !defined(BTL4GAUG_HPP) # include // the BT gauge classes (Compass, etc.) # include // the composite cluster gauges + VehicleSubSystems # include // MapDisplay (the "map" radar gauge) # include // PlayerStatus (the comm/score gauge) #endif #if !defined(L4LAMP_HPP) # include #endif #if !defined(L4WARE_HPP) # include #endif #if !defined(TERRAIN_HPP) # include #endif #if !defined(APP_HPP) # include #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); //---------------------------------------- // 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 } // //############################################################################# // 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 }