Reconstructs colorMapperMultiArmor -- tints one schematic colour (a whole torso section) by the WORST of up to 8 damage zones: - MultiArmorConnection (@004c346c/@004c34f4): scans 8 zones via entity->damageZones[idx], keeps the max damageLevel, count==0 ? 100 : Round(worst*100). - ColorMapperMultiArmor::Make/ctor (@004c3c48/@004c3d60): resolves 8 named zones to indices via Entity::GetDamageZoneIndex (13-param methodDescription). ALSO fixes a latent HEAP CORRUPTION that registering this widget exposed (and that would have blocked every further widget): GaugeInterpreter's bytecode buffer is a fixed interpreterTableSize=46864 (GAUGREND.h) tuned for RP's config, and its Insert() bounds guard is a Verify() that compiles out at DEBUG_LEVEL 0. As each BT gauge widget is registered, more of BT's larger L4GAUGE.CFG resolves into bytecode (vs being parse-skipped); colorMapperMultiArmor's 13 params x hundreds of calls pushed the total past 46864 -> silent overflow past the char[] -> heap smash detected later in mission bitmap loading (not the gauge code). Fix: interpreterTableSize -> 262144 (sized for BT's full config). Verified: parses, builds, all zones resolve, no /FORCE unresolved, combat un-regressed (TARGET DESTROYED, 0 crashes), stable. Details: docs/GAUGE_COMPOSITE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
718 lines
14 KiB
C++
718 lines
14 KiB
C++
#pragma once
|
|
|
|
#if defined(TRACE_GUAUGE_RENDERER)
|
|
extern BitTrace Gauge_Renderer;
|
|
#define SET_GUAGE_RENDERER() Gauge_Renderer.Set()
|
|
#define CLEAR_GUAGE_RENDERER() Gauge_Renderer.Clear()
|
|
#else
|
|
#define SET_GAUGE_RENDERER()
|
|
#define CLEAR_GAUGE_RENDERER()
|
|
#endif
|
|
|
|
class GaugeSymbol;
|
|
class GaugeSymbolTable;
|
|
class GaugeInterpreter;
|
|
struct ParameterDescription;
|
|
struct MethodDescription;
|
|
class GaugeRenderer;
|
|
class LampManager;
|
|
|
|
#include <fstream>
|
|
#include "renderer.h"
|
|
#include "gaugalrm.h"
|
|
#include "resource.h"
|
|
#include "gaugmap.h"
|
|
#include "gauge.h"
|
|
#include "lamp.h"
|
|
#include "wrhous.h"
|
|
|
|
struct LookupTable
|
|
{
|
|
const
|
|
char *typeString;
|
|
int
|
|
value;
|
|
|
|
int
|
|
Search(const char *string);
|
|
};
|
|
|
|
//#######################################################################
|
|
// Interpreter
|
|
//#######################################################################
|
|
typedef unsigned char GaugeInterpreterCommand;
|
|
typedef int GaugeInterpreterOffset;
|
|
|
|
class GaugeSymbol SIGNATURED
|
|
{
|
|
friend class GaugeSymbolTable;
|
|
friend class GaugeInterpreter;
|
|
public:
|
|
~GaugeSymbol(); // WARNING - do NOT destroy individual entries!
|
|
// This implementation assumes that once a symbol
|
|
// is defined, it exists until ALL symbols are
|
|
// destroyed: this allows a very simple singly-
|
|
// linked-list structure.
|
|
// Deleting an entry WILL corrupt the list.
|
|
Logical
|
|
TestInstance() const;
|
|
protected:
|
|
GaugeSymbol(
|
|
GaugeSymbol **head_pointer,
|
|
const char *label,
|
|
GaugeInterpreterOffset offset,
|
|
Logical resolved
|
|
);
|
|
|
|
char
|
|
label[32];
|
|
GaugeInterpreterOffset
|
|
offset;
|
|
Logical
|
|
resolved;
|
|
GaugeSymbol
|
|
*nextSymbol;
|
|
};
|
|
|
|
class GaugeSymbolTable SIGNATURED
|
|
{
|
|
friend class GaugeInterpreter;
|
|
public:
|
|
enum
|
|
{
|
|
errUnresolvedForwardReference = -2,
|
|
errUndefinedSymbol = -3
|
|
};
|
|
|
|
~GaugeSymbolTable();
|
|
Logical
|
|
TestInstance() const;
|
|
protected:
|
|
GaugeSymbolTable(char *table_pointer);
|
|
|
|
void
|
|
Add(const char *label, GaugeInterpreterOffset offset);
|
|
GaugeInterpreterOffset
|
|
Refer(const char *label, GaugeInterpreterOffset offset);
|
|
GaugeInterpreterOffset
|
|
Get(const char *label);
|
|
const char *
|
|
LabelFromValue(GaugeInterpreterOffset offset);
|
|
Logical
|
|
UnresolvedForwardReferences();
|
|
|
|
GaugeSymbol
|
|
*head;
|
|
char
|
|
*tablePointer;
|
|
};
|
|
|
|
class GaugeInterpreter SIGNATURED
|
|
{
|
|
friend struct MethodDescription;
|
|
friend class GaugeRenderer;
|
|
public:
|
|
~GaugeInterpreter();
|
|
Logical
|
|
TestInstance() const;
|
|
const char *
|
|
GetToken();
|
|
void
|
|
UngetPreviousToken();
|
|
Logical
|
|
GetInteger(int *int_pointer);
|
|
Logical
|
|
GetScalar(Scalar *scalar_pointer);
|
|
Logical
|
|
GetVector(Vector2DOf<int> *vector);
|
|
Logical
|
|
GetRate(GaugeRate *rate);
|
|
Logical
|
|
GetModeMask(ModeMask *mode_mask_pointer);
|
|
const char *
|
|
ReplaceVariable(const char *possible_variable_name);
|
|
void
|
|
DumpTable();
|
|
|
|
protected:
|
|
GaugeInterpreter();
|
|
|
|
void
|
|
Initialize(
|
|
const char *file_name,
|
|
MethodDescription **method_list,
|
|
Warehouse *warehouse_pointer
|
|
);
|
|
|
|
void
|
|
GetProcedureBody(
|
|
MethodDescription **method_list,
|
|
Warehouse *warehouse_pointer
|
|
);
|
|
|
|
void
|
|
ReportParsingError(
|
|
const char *string
|
|
);
|
|
|
|
Logical
|
|
ParsePrimitive(
|
|
const char *name,
|
|
MethodDescription **method_list,
|
|
Warehouse *warehouse_pointer
|
|
);
|
|
|
|
public:
|
|
void
|
|
Insert(const void *value, int size_in_chars);
|
|
void *
|
|
Retrieve(int size_in_chars);
|
|
void
|
|
InsertString(const char *string);
|
|
const char *
|
|
RetrieveString();
|
|
|
|
protected:
|
|
void
|
|
Interpret(
|
|
const char *label,
|
|
GaugeRenderer *renderer,
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity
|
|
);
|
|
|
|
void
|
|
InterpretFromOffset(
|
|
GaugeInterpreterOffset offset,
|
|
GaugeRenderer *renderer,
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity
|
|
);
|
|
|
|
enum
|
|
{
|
|
endMarker=0,
|
|
returnCommand,
|
|
setPortIndexCommand,
|
|
addOffsetCommand,
|
|
callCommand,
|
|
enableCommand,
|
|
disableCommand,
|
|
attributeVariableCommand,
|
|
nextAvailableCommand
|
|
};
|
|
|
|
enum
|
|
{
|
|
// The original (RP) value 46864 is too small for BattleTech's larger
|
|
// gauge config: as more BT gauge widgets are registered, more of
|
|
// L4GAUGE.CFG resolves into interpreter bytecode instead of being
|
|
// parse-skipped, overflowing the fixed table. The Insert() bounds guard
|
|
// is a Verify() that compiles out at DEBUG_LEVEL 0, so the overflow was
|
|
// a SILENT heap corruption (detected later in mission bitmap loading).
|
|
// Sized generously for BT's full config. (was 46864)
|
|
interpreterTableSize = 262144
|
|
};
|
|
|
|
enum
|
|
{
|
|
maxVariableNameArrayIndex = 10
|
|
};
|
|
|
|
std::filebuf file;
|
|
char currentToken[64];
|
|
Logical tokenNotTaken;
|
|
int lineNumber;
|
|
|
|
GaugeSymbolTable *symbolTable;
|
|
MethodDescription **primitiveTable;
|
|
int primitiveCount;
|
|
char *interpreterTable;
|
|
GaugeInterpreterOffset currentOffset;
|
|
const char *attributeNameArray[maxVariableNameArrayIndex];
|
|
};
|
|
|
|
//#######################################################################
|
|
// ParameterDescription
|
|
//#######################################################################
|
|
# define PARAMETER_DESCRIPTION_END \
|
|
{ ParameterDescription::typeEmpty, NULL }
|
|
struct ParameterDescription
|
|
{
|
|
enum ParameterType
|
|
{
|
|
typeEmpty = 0,
|
|
typeRate,
|
|
typeModeMask,
|
|
typeInteger,
|
|
typeColor,
|
|
typeScalar,
|
|
typeVector,
|
|
typeRectangle,
|
|
typeAttribute,
|
|
typeString
|
|
};
|
|
|
|
ParameterType
|
|
type;
|
|
enum
|
|
{
|
|
maxStringLength=64
|
|
};
|
|
|
|
union
|
|
{
|
|
// 'nextMethodList' is used to chain to the next method list...
|
|
MethodDescription **nextMethodList;
|
|
GaugeRate rate;
|
|
ModeMask modeMask;
|
|
int integer;
|
|
int color;
|
|
Scalar scalar;
|
|
BitMap *bitmap;
|
|
PixelMap8 *pixelmap;
|
|
Palette8 *palette;
|
|
void *attributePointer;
|
|
|
|
// can't use Vector2DOf<int> because constructor not allowed here!
|
|
struct
|
|
{
|
|
int x, y;
|
|
}
|
|
vector;
|
|
|
|
// can't use Rectangle2D because constructor not allowed here!
|
|
struct
|
|
{
|
|
struct
|
|
{
|
|
int x, y;
|
|
}
|
|
bottomLeft;
|
|
|
|
struct
|
|
{
|
|
int x, y;
|
|
}
|
|
topRight;
|
|
}
|
|
rectangle;
|
|
|
|
char string[maxStringLength];
|
|
}
|
|
data;
|
|
|
|
~ParameterDescription();
|
|
|
|
void
|
|
ShowInstance(char *indent);
|
|
void
|
|
CheckIt(int type);
|
|
void
|
|
Save(GaugeInterpreter *interpreter);
|
|
void
|
|
Restore(
|
|
GaugeInterpreter *interpreter,
|
|
Entity *entity
|
|
);
|
|
void
|
|
DumpInterpreterEntry(
|
|
GaugeInterpreter *interpreter,
|
|
const char *indent
|
|
);
|
|
void *
|
|
ParseAttribute(const char *string_pointer, Entity *entity);
|
|
Logical
|
|
Extract(
|
|
GaugeInterpreter *interpreter,
|
|
Warehouse *warehouse_pointer
|
|
);
|
|
};
|
|
|
|
//#######################################################################
|
|
// MethodDescription
|
|
//#######################################################################
|
|
# define METHOD_DESCRIPTION_CHAIN(pointer) \
|
|
{NULL, NULL, {{ ParameterDescription::typeEmpty, pointer }}}
|
|
|
|
struct MethodDescription
|
|
{
|
|
enum
|
|
{
|
|
MaximumParameters = 16
|
|
};
|
|
|
|
char
|
|
*name;
|
|
|
|
Logical
|
|
(*execute)(
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *renderer
|
|
);
|
|
|
|
ParameterDescription
|
|
parameterList[MaximumParameters];
|
|
|
|
void
|
|
ShowInstance(char *indent);
|
|
void
|
|
Execute(
|
|
int display_port_index,
|
|
Vector2DOf<int> position,
|
|
Entity *entity,
|
|
GaugeRenderer *renderer
|
|
);
|
|
};
|
|
|
|
//#######################################################################
|
|
// GaugeRenderer
|
|
//#######################################################################
|
|
struct GaugeRendererStatistics
|
|
{
|
|
int
|
|
sampleCount;
|
|
Scalar
|
|
sum,
|
|
maximum;
|
|
|
|
void
|
|
Clear(),
|
|
Update(Scalar delta);
|
|
Scalar
|
|
CalculateAverage();
|
|
};
|
|
|
|
|
|
class GaugeRenderer:
|
|
public Renderer
|
|
{
|
|
friend class Gauge;
|
|
friend class GaugeInterpreter;
|
|
friend Scalar draw_bar(
|
|
GaugeRenderer *renderer,
|
|
int bar_width,
|
|
int slot_index,
|
|
int bar_type
|
|
);
|
|
public:
|
|
enum
|
|
{
|
|
maximumGraphicsPorts = 16
|
|
};
|
|
//--------------------------------------------------------------------
|
|
// Construction, Destruction, Testing
|
|
//--------------------------------------------------------------------
|
|
GaugeRenderer();
|
|
~GaugeRenderer();
|
|
|
|
static void
|
|
EmergencyShutdown();
|
|
|
|
virtual void
|
|
LocalEmergencyShutdown();
|
|
|
|
Logical
|
|
TestInstance() const;
|
|
|
|
LampManager*
|
|
GetLampManager()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
return lampManager;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Entity-related methods
|
|
//
|
|
// These are virtual functions defined by the Renderer class.
|
|
// Derived classes call these methods if the derived class
|
|
// doesn't do anything special about the entity.
|
|
//--------------------------------------------------------------------
|
|
void
|
|
LinkToEntity(Entity *entity);
|
|
void
|
|
NotifyOfNewInterestingEntity(Entity *entity);
|
|
void
|
|
NotifyOfBecomingUninterestingEntity(Entity *entity);
|
|
void
|
|
StartEntityAlarmImplementation(
|
|
Entity *entity,
|
|
Subsystem *subsystem,
|
|
Enumeration condition,
|
|
ResourceDescription::ResourceID resource_ID
|
|
);
|
|
void
|
|
StopEntityAlarmImplementation(
|
|
Entity *entity,
|
|
Subsystem *subsystem,
|
|
Enumeration condition
|
|
);
|
|
//--------------------------------------------------------------------
|
|
// LoadMissionImplementation
|
|
// ShutdownImplementation
|
|
// SuspendImplementation
|
|
// ResumeImplementation
|
|
//
|
|
// These are virtual functions defined by the Renderer class.
|
|
// Derived classes must call these methods.
|
|
//--------------------------------------------------------------------
|
|
void
|
|
LoadMissionImplementation(Mission *mission);
|
|
void
|
|
ShutdownImplementation();
|
|
void
|
|
SuspendImplementation();
|
|
void
|
|
ResumeImplementation();
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Video effects
|
|
// HACK!!!!!!!!
|
|
// Quick and dirty hack to allow calling L4GaugeRenderer::SpecialEffect
|
|
// from non L4 level. GDU 2/28/96
|
|
//--------------------------------------------------------------------
|
|
public:
|
|
enum VideoEffectType
|
|
{
|
|
scrambleVideo
|
|
};
|
|
|
|
virtual void
|
|
SpecialEffect(VideoEffectType type, Scalar duration) {};
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// GetGraphicsPort
|
|
//--------------------------------------------------------------------
|
|
//
|
|
int
|
|
FindGraphicsPort(const char * port_name);
|
|
|
|
GraphicsPort
|
|
*GetGraphicsPort(const char *port_name);
|
|
|
|
GraphicsPort
|
|
*GetGraphicsPort(int port_number);
|
|
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// GaugeEntityList operations
|
|
//--------------------------------------------------------------------
|
|
//
|
|
int
|
|
GetMovingEntities(
|
|
GaugeEntityList *destination_list
|
|
)
|
|
{
|
|
return movingEntities.CopyEntities(
|
|
destination_list
|
|
);
|
|
}
|
|
|
|
int
|
|
GetMovingEntitiesWithinBounds(
|
|
GaugeEntityList *destination_list,
|
|
Scalar minX,
|
|
Scalar minY,
|
|
Scalar minZ,
|
|
Scalar maxX,
|
|
Scalar maxY,
|
|
Scalar maxZ
|
|
)
|
|
{
|
|
return movingEntities.CopyEntitiesWithinBounds(
|
|
destination_list,
|
|
minX, minY, minZ,
|
|
maxX, maxY, maxZ
|
|
);
|
|
}
|
|
|
|
int
|
|
GetStaticEntities(
|
|
GaugeEntityList *destination_list
|
|
)
|
|
{
|
|
return staticEntities.CopyEntities(
|
|
destination_list
|
|
);
|
|
}
|
|
int
|
|
GetStaticEntitiesWithinBounds(
|
|
GaugeEntityList *destination_list,
|
|
Scalar minX,
|
|
Scalar minY,
|
|
Scalar minZ,
|
|
Scalar maxX,
|
|
Scalar maxY,
|
|
Scalar maxZ
|
|
)
|
|
{
|
|
return staticEntities.CopyEntitiesWithinBounds(
|
|
destination_list,
|
|
minX, minY, minZ,
|
|
maxX, maxY, maxZ
|
|
);
|
|
}
|
|
void
|
|
GetStaticBounds(
|
|
Scalar *min_x,
|
|
Scalar *min_y,
|
|
Scalar *min_z,
|
|
Scalar *max_x,
|
|
Scalar *max_y,
|
|
Scalar *max_z
|
|
)
|
|
{
|
|
staticEntities.GetBounds(
|
|
min_x, min_y, min_z,
|
|
max_x, max_y, max_z
|
|
);
|
|
}
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Configure
|
|
//--------------------------------------------------------------------
|
|
//
|
|
virtual void
|
|
Configure(
|
|
const char *configuration_name,
|
|
Entity *entity
|
|
);
|
|
|
|
int
|
|
parseConfigurationLine(
|
|
const char *entry,
|
|
char *buffer,
|
|
char **item_pointer,
|
|
int max_items
|
|
);
|
|
|
|
//--------------------------------------------------------------------
|
|
// Gauge methods
|
|
//--------------------------------------------------------------------
|
|
void
|
|
Add(GaugeBase *new_base),
|
|
Remove(unsigned int ownerID),
|
|
Inactivate(GaugeBase *the_base);
|
|
|
|
GaugeRate
|
|
FindBestFirstTierRate(),
|
|
FindBestSecondTierRate(),
|
|
FindBestThirdTierRate(),
|
|
FindBestFourthTierRate();
|
|
//--------------------------------------------------------------------
|
|
// ExecuteImplementation
|
|
//--------------------------------------------------------------------
|
|
protected:
|
|
void
|
|
ExecuteImplementation(
|
|
RendererComplexity complexity_update,
|
|
RendererOrigin::InterestingEntityIterator *iterator
|
|
);
|
|
|
|
public:
|
|
Logical
|
|
ExecuteBackground();
|
|
|
|
protected:
|
|
void
|
|
ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask),
|
|
DeactivateGaugeBases(ModeMask current_mode_mask);
|
|
Logical
|
|
ProcessOneActiveGauge();
|
|
virtual void
|
|
ExecuteForeground();
|
|
virtual Logical
|
|
ExecuteBackgroundDisplayUpdate();
|
|
//--------------------------------------------------------------------
|
|
// Profiling support
|
|
//--------------------------------------------------------------------
|
|
protected:
|
|
virtual Scalar
|
|
GetCurrentFramePercentage();
|
|
public:
|
|
void
|
|
ProfileReport();
|
|
//--------------------------------------------------------------------
|
|
// Configuration parsing methods
|
|
//--------------------------------------------------------------------
|
|
protected:
|
|
void
|
|
BuildConfigurationFile(
|
|
const char *file_name,
|
|
MethodDescription **method_description
|
|
);
|
|
//--------------------------------------------------------------------
|
|
// Public data
|
|
//--------------------------------------------------------------------
|
|
public:
|
|
Warehouse
|
|
*warehousePointer;
|
|
GaugeInterpreter
|
|
*interpreter;
|
|
|
|
int GetTaskMode() { return taskMode; }
|
|
//--------------------------------------------------------------------
|
|
// Protected data
|
|
//--------------------------------------------------------------------
|
|
protected:
|
|
GraphicsPort *graphicsPort[maximumGraphicsPorts];
|
|
GaugeEntityList movingEntities;
|
|
GaugeEntityArray staticEntities;
|
|
LampManager *lampManager;
|
|
GaugeAlarmManager *gaugeAlarmManager;
|
|
|
|
enum
|
|
{
|
|
foreground,
|
|
background,
|
|
copy
|
|
}
|
|
taskMode;
|
|
|
|
private:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// Private data
|
|
//--------------------------------------------------------------------
|
|
//
|
|
ModeMask
|
|
previousModeMask;
|
|
SChainOf<GaugeBase*>
|
|
newList,
|
|
activeList,
|
|
inactiveList;
|
|
SChainIteratorOf<GaugeBase*>
|
|
*activeIterator;
|
|
Logical
|
|
suspended;
|
|
GaugeRate
|
|
rateBitMask;
|
|
int
|
|
rateProfileIndex;
|
|
static GaugeRenderer
|
|
*headGaugeRenderer;
|
|
GaugeRenderer
|
|
*nextGaugeRenderer;
|
|
//-----------------------------------
|
|
// Load-balancing data and profiling
|
|
//-----------------------------------
|
|
enum
|
|
{
|
|
slotCount = 16,
|
|
tierCount=5
|
|
};
|
|
|
|
Scalar
|
|
load[slotCount];
|
|
GaugeRendererStatistics
|
|
statistics[slotCount][tierCount];
|
|
};
|