Files
arcattackandClaude Opus 4.8 a256813395 gauges: secondary/radar MFD composites live on a dev box (Milestone B)
The pod's secondary/radar cockpit surface now renders as an inset in the
800x600 dev window under BT_DEV_GAUGES: radar/tactical grid, SPEED/HEADING/
MAGNETIC/PROP dials, and the color-coded ARMOR DAMAGE mech schematic -- real
gauge content (nzSec=27247), composited from the shared CPU pixelBuffer.

Composite pass (engine): SVGA16::DrawDevInset palette-expands the secondary
plane into a MANAGED texture on the MAIN device and draws an XYZRHW inset quad;
BTDrawGaugeInset() reaches the gauge renderer's 'sec' port and is called from
DPLRenderer::ExecuteImplementation as the last draw before EndScene.

Three reconstruction bugs fixed to get real content:
1. BTL4Application::MakeGaugeRenderer signature mismatch (REAL fix): the
   reconstructed no-arg override only HID the 2007-engine's widened 3-arg
   virtual MakeGaugeRenderer(int*,int*,int*), so the engine built a base
   L4GaugeRenderer whose ctor never parsed gauge/l4gauge.cfg -> empty symbol
   table -> "undefined label 'bhk1Init'" -> no ports/gauges. Matched the 3-arg
   signature so it truly overrides (args ignored; BT is fullscreen). Same bug
   class as the BTL4GaugeRenderer(false,NULL,NULL,NULL) ctor fix.
2. Parse hung on undefined primitives (gated dev accommodation): the BT gauge
   primitive table (BTL4MethodDescription) is still a stub, so an unknown
   primitive -> ReportParsingError -> Fail() -> a MODAL dialog freezing the
   parse. Under BT_DEV_GAUGES, skip the unknown primitive's params so labels
   register and the base "configure" primitive builds the ports.
3. Gauge widgets AV on NULL data bindings (gated): NumericDisplayScalar's NULL
   value_pointer -> GaugeConnectionDirectOf ctor deref (bind NULL->static zero);
   RankAndScore::Execute derefs unreconstructed game state (Gauge::GuardedExecute
   SEH wrapper -> Disable(True) on first fault).

All guards gated on BT_DEV_GAUGES: default DEV un-regressed (TARGET DESTROYED,
0 crashes) and the pod path is byte-unchanged (strict Fail, no guards).

Remaining (docs/GAUGE_COMPOSITE.md): the real gauge WIDGET reconstruction
(BTL4MethodDescription method table + gauge->game-state data bindings), then
Step 2 (RP<->BT MFD port-name reconcile) + Step 3 (2-window layout).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 10:59:45 -05:00

430 lines
11 KiB
C++

#pragma once
#include "style.h"
typedef unsigned int GaugeRate;
class GaugeRenderer;
class GaugeBase;
class GraphicGaugeBackground;
class Gauge;
class GraphicGauge;
class GaugeConnection;
class Entity;
class GaugeAlarmManager;
#include "mode.h"
#include "slot.h"
#include "chain.h"
#include "receiver.h"
#include "graph2d.h"
//#########################################################################
//############################# GaugeBase #################################
//#########################################################################
class GaugeBase :
public Node
{
friend class GaugeRenderer;
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------
protected:
GaugeBase(
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
const char *identification_string
);
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
public:
virtual ~GaugeBase();
//----------------------------------------------------------------------
// Test methods
//----------------------------------------------------------------------
Logical
TestInstance() const;
//----------------------------------------------------------------------
// Update methods
//----------------------------------------------------------------------
virtual void
BecameActive(),
BecameInactive(),
Inactivate(),
UpdateProfile(Scalar frame_percentage),
ReportProfile();
virtual Logical
Update(GaugeRate rate_mask);
virtual void
LinkToEntity(Entity *entity),
NotifyOfNewInterestingEntity(Entity *entity),
NotifyOfBecomingUninterestingEntity(Entity *entity);
virtual int
DiscernTier();
//----------------------------------------------------------------------
// Public data
//----------------------------------------------------------------------
public:
Logical
alreadyActivatedFlag; // This is really a visibility flag.
// Active/inactive lists are more like
// "should get redrawn" lists
//----------------------------------------------------------------------
// Protected data
//----------------------------------------------------------------------
protected:
Logical
stayInactive; // used by GaugeRenderer during activation
unsigned int
ownerID;
ModeMask
modeMask;
GaugeRenderer
*renderer;
const char
*identificationString;
};
//#########################################################################
//########################### GaugeBackground #############################
//#########################################################################
class GaugeBackground :
public GaugeBase
{
protected:
GaugeBackground(
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
const char *identification_string = "GraphicGaugeBackground"
);
};
//#########################################################################
//######################## GraphicGaugeBackground #########################
//#########################################################################
class GraphicGaugeBackground :
public GaugeBackground
{
protected:
GraphicGaugeBackground(
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
int graphics_port_number,
const char *identification_string = "GraphicGaugeBackground"
);
//----------------------------------------------------------------------
// Protected data
//----------------------------------------------------------------------
GraphicsView
localView;
};
//#########################################################################
//########################## GaugeConnection ##############################
//#########################################################################
// The GaugeConnection object maintains one instance of a mapping from
// a value in some location to a parameter for a gauge.
class GaugeConnection :
public Plug
{
friend class Gauge;
public:
GaugeConnection(int parameter_ID);
~GaugeConnection();
Logical
TestInstance() const;
protected:
virtual void ShowInstance(char *indent);
virtual void Update();
int parameterID;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GaugeConnectionDirectOf ~~~~~~~~~~~~~~~~~~
template <class T> class GaugeConnectionDirectOf:
public GaugeConnection
{
friend class Gauge;
public:
GaugeConnectionDirectOf(
int parameter_ID,
T* data_destination,
T* data_source
);
~GaugeConnectionDirectOf();
Logical
TestInstance() const;
protected:
void
Update();
void
ShowInstance(char *indent);
T *dataSource;
T *dataDestination;
};
template <class T> GaugeConnectionDirectOf<T>::GaugeConnectionDirectOf(
int parameter_ID,
T* data_destination,
T* data_source
):
GaugeConnection(parameter_ID),
dataSource(data_source),
dataDestination(data_destination)
{
Check_Pointer(this);
Check_Pointer(data_destination);
//
// BT DEV-GAUGES bring-up: some gauge widgets bind to mech data sources that
// are not reconstructed yet, so the attribute resolves to a NULL data_source
// (see the "(Scalar *) is VERY dangerous!" note in L4GAUGE.cpp). Rather than
// AV here (and later in Update()), bind to a static zero so the gauge simply
// reads 0. Gated on BT_DEV_GAUGES so the POD path is byte-unchanged.
//
if (data_source == NULL)
{
static int s_devGauges = -1;
if (s_devGauges < 0)
s_devGauges = (getenv("BT_DEV_GAUGES") != NULL) ? 1 : 0;
if (s_devGauges)
{
static T s_gaugeNullSource = T();
dataSource = &s_gaugeNullSource;
data_source = &s_gaugeNullSource;
}
}
Check_Pointer(data_source);
*dataDestination = *dataSource;
Verify(*dataDestination == *dataSource);
Check(this);
}
template <class T> GaugeConnectionDirectOf<T>::~GaugeConnectionDirectOf()
{}
template <class T> void
GaugeConnectionDirectOf<T>::Update()
{
Check(this);
Check_Pointer(dataSource);
Check_Pointer(dataDestination);
*dataDestination = *dataSource;
Verify(*dataDestination == *dataSource);
Check(this);
}
template <class T> void
GaugeConnectionDirectOf<T>::ShowInstance(char *indent)
{
Check(this);
Check_Pointer(dataSource);
Check_Pointer(dataDestination);
std::cout << indent << "GaugeConnectionDirectOf:\n";
std::cout << indent << "...dataSource at" <<
dataSource << "=" << *dataSource << "\n";
std::cout << indent << "...dataDestination at" <<
dataSource << "\n" << std::flush;
GaugeConnection::ShowInstance(indent);
}
template <class T> Logical
GaugeConnectionDirectOf<T>::TestInstance() const
{
Check_Pointer(this);
Check_Pointer(dataSource);
Check_Pointer(dataDestination);
return Plug::TestInstance();
}
//#########################################################################
//################################# Gauge #################################
//#########################################################################
class Gauge :
public GaugeBase
{
public:
enum
{
gaugeRate_A=0xFFFF, // every frame
gaugeRate_B=0xAAAA, // every other frame
gaugeRate_C=0x5555,
gaugeRate_D=0x8888, // every 4th frame
gaugeRate_E=0x4444,
gaugeRate_F=0x2222,
gaugeRate_G=0x1111,
gaugeRate_H=0x8080, // every 8th frame
gaugeRate_I=0x4040,
gaugeRate_J=0x2020,
gaugeRate_K=0x1010,
gaugeRate_L=0x0808,
gaugeRate_M=0x0404,
gaugeRate_N=0x0202,
gaugeRate_O=0x0101,
gaugeRate_P=0x8000, // every 16th frame
gaugeRate_Q=0x4000,
gaugeRate_R=0x2000,
gaugeRate_S=0x1000,
gaugeRate_T=0x0800,
gaugeRate_U=0x0400,
gaugeRate_V=0x0200,
gaugeRate_W=0x0100,
gaugeRate_X=0x0080,
gaugeRate_Y=0x0040,
gaugeRate_Z=0x0020,
gaugeRate_Z0=0x0010,
gaugeRate_Z1=0x0008,
gaugeRate_Z2=0x0004,
gaugeRate_Z3=0x0002,
gaugeRate_Z4=0x0001
};
//----------------------------------------------------------------------
// Public static methods and data
//----------------------------------------------------------------------
static GaugeRate
rateTable[31];
static GaugeRate
NextFirstTierGaugeRate(), // returns either B,C
NextSecondTierGaugeRate(), // returns DEFG
NextThirdTierGaugeRate(), // returns HIJKLMNO
NextFourthTierGaugeRate(); // returns PQRSTUVWXYZ
static GaugeRate
ConvertIndexToRate(int index);
//----------------------------------------------------------------------
// Constructor method
//----------------------------------------------------------------------
Gauge(
GaugeRate new_rate,
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
const char *identification_string = "Gauge"
);
//----------------------------------------------------------------------
// Destructor method
//----------------------------------------------------------------------
~Gauge();
//----------------------------------------------------------------------
// Test methods
//----------------------------------------------------------------------
Logical
TestInstance() const;
void
ShowInstance(char *indent);
int
DiscernTier();
static Logical
TestClass();
//----------------------------------------------------------------------
// Connection methods
//----------------------------------------------------------------------
virtual void
AddConnection(GaugeConnection *connection),
RemoveConnection(int parameter_ID),
RemoveAllConnections();
//----------------------------------------------------------------------
// Update methods
//----------------------------------------------------------------------
void
Disable(Logical disable_state);
Logical
Update(GaugeRate rate_mask);
protected:
virtual void
Execute(); // Execute internal processes to display the gauge
// BT DEV-GAUGES bring-up: SEH wrapper around Execute() so a gauge whose
// game-state data binding isn't reconstructed yet is skipped (not crashed).
// Returns False if Execute() raised a structured exception (e.g. an AV).
Logical
GuardedExecute();
//----------------------------------------------------------------------
// Protected data
//----------------------------------------------------------------------
protected:
GaugeRate
rate,
oldRate;
ChainOf<GaugeConnection*>
instanceList;
//---------------------------------------
// Profiling data
//---------------------------------------
void
UpdateProfile(Scalar frame_percentage),
ReportProfile();
Scalar
profileFramePercentage,
profileMaxFramePercentage;
int
profileCycles;
};
//#########################################################################
//############################# GraphicGauge ##############################
//#########################################################################
class GraphicGauge :
public Gauge
{
public:
//
//----------------------------------------------------------------------
// Public methods
//----------------------------------------------------------------------
//
GraphicGauge(
GaugeRate new_rate,
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
int graphics_port_number,
const char *identification_string = "GraphicGauge"
);
~GraphicGauge();
Logical
TestInstance() const;
void
ShowInstance(char *indent);
//----------------------------------------------------------------------
// Public data
//----------------------------------------------------------------------
GraphicsView
localView;
};