//===========================================================================//
// 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
#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);

	//----------------------------------------
	// 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
}
