Files
BT411/engine/MUNGA/GAUGREND.cpp
T
arcattackandClaude Opus 4.8 070af409f7 gauge wave P1a: publish heat/power/weapon attributes + radar zoom
The gauge-databinding-map workflow found most cockpit gauges resolve NULL
because the reconstructed subsystems publish only a fraction of the attributes
the config binds.  First publishing batch (attribute tables are read-only static
data; ids kept a dense prefix from each parent's NextAttributeID):

- HeatSink table dense-append: DegradationTemperature/FailureTemperature (the
  condenser temp-bar warn/max endpoints -- were NULL, so the two-part bars could
  not scale), NormalizedPressure/DegradationPressure/CoolantMassLeakRate, and the
  HeatSink link.  Condenser/Reservoir inherit this -> all 6 condenser temp bars
  now resolve current/warn/max (verified: BT_GAUGE_ATTR_LOG all OK).
- PoweredSubsystem::GetAttributeIndex() (new) publishes InputVoltage->voltageSource
  -- the cluster power-branch gate (the power-lamp/generator-voltage/state-lamp
  sub-branch is skipped when it resolves NULL).  Flows to Sensor/Myomers/weapons.
- MechWeapon::GetAttributeIndex() (new) publishes OutputVoltage/PercentDone->
  rechargeLevel; Emitter/PPC/ProjectileWeapon/MissileLauncher/GaussRifle DefaultData
  re-pointed at it (they carried an EMPTY default-constructed index -> resolved
  NOTHING).  Verified: the ER MED LASER / PPC / STREAK weapon clusters now render
  live recharge dials (were blank TEMP/STATUS).
- Mech::SetTargetRange un-stubbed (radarRange = range) -> the radar map scale +
  overlay range readout track the mapper's zoom (was frozen at 1000).
- GAUGREND ParseAttribute: env-gated per-binding resolution trace (BT_GAUGE_ATTR_LOG)
  -- durable diagnostic infra for the wave.

Verified DBASE+dev gauges: no startup/gauge-construction crash (dense chain intact),
combat un-regressed (TARGET DESTROYED), clusters build with InputVoltage resolving.
Remaining config-binding NULLs: HeatSink/AmbientTemperature (aggregate bank, P3) +
Searchlight/LightOn (P1b).

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

4293 lines
98 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "gaugrend.h"
#include "lamp.h"
#include "mover.h"
#include "terrain.h"
#include "app.h"
#include "hostmgr.h" // HostManager + AllEntityIterator (RebuildEntityGrid)
// #define LOCAL_TEST
#if defined(LOCAL_TEST)
# define Test_Tell(n) DEBUG_STREAM << n
#else
# define Test_Tell(n)
#endif
#define PROFILE_GAUGES
#if defined(TRACE_GAUGE_RENDERER)
BitTrace Gauge_Renderer("Gauge Renderer");
#endif
//#######################################################################
// Miscellaneous utilities
//#######################################################################
int
LookupTable::Search(const char *string)
{
Check_Pointer(this);
Verify(string != NULL);
LookupTable
*table = this;
for(; table->typeString!=NULL; ++table)
{
if (stricmp(string, table->typeString) == 0)
{
break;
}
}
Check_Fpu();
return table->value;
}
//#######################################################################
// GaugeSymbol
//#######################################################################
GaugeSymbol::GaugeSymbol(
GaugeSymbol **head_pointer,
const char *new_label,
GaugeInterpreterOffset new_offset,
Logical new_resolved
)
{
Check(this);
Check_Pointer(head_pointer);
Check_Pointer(new_label);
Test_Tell(
"GaugeSymbol::GaugeSymbol(" << head_pointer <<
"," << new_label <<
"," << new_offset <<
"," << new_resolved <<
")\n"
);
nextSymbol = *head_pointer;
*head_pointer = this;
Str_Copy(label, new_label, sizeof(label));
offset = new_offset;
resolved = new_resolved;
Check_Fpu();
}
GaugeSymbol::~GaugeSymbol()
{
Check(this);
Check_Fpu();
}
Logical
GaugeSymbol::TestInstance() const
{
return True;
}
//#######################################################################
// GaugeSymbolTable
//#######################################################################
GaugeSymbolTable::GaugeSymbolTable(char *table_pointer)
{
Test_Tell(
"GaugeSymbolTable::GaugeSymbolTable(" << ((void *) table_pointer) <<
")\n"
);
Check_Pointer(this);
head = NULL;
tablePointer = table_pointer;
Check_Fpu();
}
GaugeSymbolTable::~GaugeSymbolTable()
{
Test_Tell(
"GaugeSymbolTable::~GaugeSymbolTable()\n"
);
Check(this);
GaugeSymbol
*symbol,
*next_symbol;
for(symbol=head; symbol!=NULL; symbol=next_symbol)
{
Check(symbol);
next_symbol = symbol->nextSymbol;
Unregister_Object(symbol);
delete symbol;
}
head = NULL;
Check_Fpu();
}
Logical
GaugeSymbolTable::TestInstance() const
{
return True;
}
void
GaugeSymbolTable::Add(const char *label, GaugeInterpreterOffset new_offset)
{
Check(this);
Check_Pointer(label);
Test_Tell(
"GaugeSymbolTable::Add(" << label <<
"," << new_offset <<
")\n"
);
GaugeSymbol
*symbol;
//-------------------------------------------------
// Check to see if this label already exists
//-------------------------------------------------
for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
{
Check(symbol);
if (stricmp(label, symbol->label) == 0)
{
Test_Tell("Exists.\n");
//-------------------------------------------------
// It DOES exist. Has it already been resolved?
//-------------------------------------------------
if (!symbol->resolved)
{
Test_Tell("Unresolved.\n");
//-------------------------------------------------
// No, resolve all forward references to it
//-------------------------------------------------
// Forward references (references to undefined
// labels) are saved as a singly-linked list
// of offsets within the table itself: each
// reference to the label contains an offset to
// the previous reference. The list is
// terminated by an offset of -1.
//-------------------------------------------------
GaugeInterpreterOffset
table_offset,
next_offset,
*offset_pointer;
for (
table_offset=symbol->offset;
table_offset>=0;
table_offset = next_offset)
{
Test_Tell("Resolving " << table_offset << "\n");
offset_pointer =
(GaugeInterpreterOffset *) &tablePointer[table_offset];
next_offset = *offset_pointer;
*offset_pointer = (GaugeInterpreterOffset) new_offset;
}
symbol->offset = new_offset;
symbol->resolved = True;
Test_Tell("Done!\n");
Check_Fpu();
return;
}
else
{
Test_Tell("Resolved?!?!?.\n");
//-------------------------------------------------
// Yes, this is an error. Throw a fit.
//-------------------------------------------------
DEBUG_STREAM << "label =" << label << "\n" << std::flush;
Fail("Already resolved");
}
}
}
//-------------------------------------------------
// This is a new, resolved definition: just add it
//-------------------------------------------------
Test_Tell("New.\n");
# if DEBUG_LEVEL > 0
symbol = new GaugeSymbol(&head, label, new_offset, True);
Check(symbol);
Register_Object(symbol);
# else
new GaugeSymbol(&head, label, new_offset, True);
# endif
Check_Fpu();
}
GaugeInterpreterOffset
GaugeSymbolTable::Refer(
const char *label,
GaugeInterpreterOffset new_offset
)
{
Check(this);
Check_Pointer(label);
Test_Tell(
"GaugeSymbolTable::Refer(" << label <<
"," << new_offset <<
")\n"
);
GaugeSymbol
*symbol;
//-------------------------------------------------
// Check to see if this label already exists
//-------------------------------------------------
for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
{
Check(symbol);
if (stricmp(label, symbol->label) == 0)
{
Test_Tell("Exists.\n");
//-------------------------------------------------
// It DOES exist. Is it resolved?
//-------------------------------------------------
if (symbol->resolved)
{
Test_Tell("Resolved.\n");
//-------------------------------------------------
// Yes, return the value.
//-------------------------------------------------
Check_Fpu();
return symbol->offset;
}
else
{
Test_Tell("Unresolved.\n");
//-------------------------------------------------
// No, add to the list of forward references.
//-------------------------------------------------
GaugeInterpreterOffset
previous_offset = symbol->offset;
Test_Tell("Returning previous " << previous_offset << ".\n");
symbol->offset = new_offset;
Check_Fpu();
return previous_offset;
}
}
}
//-------------------------------------------------
// This is a new forward reference.
// A (-1) is returned to mark the end of
// the reference chain.
//
// IT IS NOT AN ERROR!
//-------------------------------------------------
Test_Tell("New.\n");
# if DEBUG_LEVEL > 0
symbol = new GaugeSymbol(&head, label, new_offset, False);
Check(symbol);
Register_Object(symbol);
# else
new GaugeSymbol(&head, label, new_offset, False);
# endif
Check_Fpu();
return -1;
}
GaugeInterpreterOffset
GaugeSymbolTable::Get(const char *label)
{
Test_Tell(
"GaugeSymbolTable::Get(" << label <<
")\n"
);
Check(this);
Check_Pointer(label);
GaugeSymbol
*symbol;
//-------------------------------------------------
// Check to see if this label exists
//-------------------------------------------------
for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
{
Check(symbol);
if (stricmp(label, symbol->label) == 0)
{
Test_Tell("Exists.\n");
//-------------------------------------------------
// It DOES exist. Is it resolved?
//-------------------------------------------------
if (symbol->resolved)
{
Test_Tell("Resolved.\n");
//-------------------------------------------------
// Yes, return the value.
//-------------------------------------------------
Check_Fpu();
return symbol->offset;
}
else
{
Test_Tell("Unresolved (error).\n");
//-------------------------------------------------
// Return error.
//-------------------------------------------------
Check_Fpu();
return errUnresolvedForwardReference;
}
}
}
//-------------------------------------------------
// Undefined, return error.
//-------------------------------------------------
Test_Tell("Undefined (error).\n");
Check_Fpu();
return errUndefinedSymbol;
}
const char *
GaugeSymbolTable::LabelFromValue(GaugeInterpreterOffset value)
{
# if defined SHOW_EVERYTHING
Test_Tell(
"GaugeSymbolTable::LabelFromValue(" << value <<
")\n"
);
# endif
Check(this);
GaugeSymbol
*symbol;
//-------------------------------------------------
// Check to see if this label exists
//-------------------------------------------------
for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
{
Check(symbol);
if (symbol->offset == value)
{
//-------------------------------------------------
// It DOES exist. Is it resolved?
//-------------------------------------------------
if (symbol->resolved)
{
//-------------------------------------------------
// Yes, return the value.
//-------------------------------------------------
Check_Fpu();
return symbol->label;
}
else
{
//-------------------------------------------------
// Return error.
//-------------------------------------------------
Check_Fpu();
return NULL;
}
}
}
//-------------------------------------------------
// Undefined, return error.
//-------------------------------------------------
Check_Fpu();
return NULL;
}
Logical
GaugeSymbolTable::UnresolvedForwardReferences()
{
Test_Tell(
"GaugeSymbolTable::UnresolvedForwardReferences()\n"
);
Check(this);
GaugeSymbol
*symbol;
//-------------------------------------------------
// Check for unrersolved symbols
//-------------------------------------------------
for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol)
{
Test_Tell("Symbol '" << symbol->label << "' at " << symbol << "\n");
Check(symbol);
if (!symbol->resolved)
{
Test_Tell("Unresolved!\n");
Check_Fpu();
return True;
}
}
//-------------------------------------------------
// Everything is resolved!
//-------------------------------------------------
Test_Tell("All is resolved.\n");
Check_Fpu();
return False;
}
//#######################################################################
// GaugeInterpreter
//#######################################################################
GaugeInterpreter::GaugeInterpreter()
{
Test_Tell("GaugeInterpreter::GaugeInterpreter()\n");
Check_Pointer(this);
//-------------------------------------------------
// Create interpreter table
//-------------------------------------------------
interpreterTable = new char[interpreterTableSize];
Check_Pointer(interpreterTable);
Register_Pointer(interpreterTable);
//-------------------------------------------------
// Clear attribute variable array
//-------------------------------------------------
for (int i=0; i<maxVariableNameArrayIndex; ++i)
{
attributeNameArray[i] = NULL;
}
//-------------------------------------------------
// Create empty symbol table
//-------------------------------------------------
symbolTable = new GaugeSymbolTable(interpreterTable);
Check(symbolTable);
Register_Object(symbolTable);
primitiveTable = NULL;
primitiveCount = 0;
currentOffset = 0;
Check_Fpu();
}
GaugeInterpreter::~GaugeInterpreter()
{
Test_Tell("GaugeInterpreter::~GaugeInterpreter()\n");
Check(this);
//-------------------------------------------------
// Delete primitive table
//-------------------------------------------------
if (primitiveTable != NULL)
{
Check_Pointer(primitiveTable);
Unregister_Pointer(primitiveTable);
delete[] primitiveTable;
}
//-------------------------------------------------
// Delete symbol table
//-------------------------------------------------
Check(symbolTable);
Unregister_Object(symbolTable);
delete symbolTable;
//-------------------------------------------------
// Delete interpreter table
//-------------------------------------------------
Check_Pointer(interpreterTable);
Unregister_Pointer(interpreterTable);
delete[] interpreterTable;
Check_Fpu();
}
Logical
GaugeInterpreter::TestInstance() const
{
return True;
}
const char *
GaugeInterpreter::GetToken()
{
# if defined(SHOW_EVERYTHING)
Test_Tell("GetToken()\n");
# endif
Check(this);
if (tokenNotTaken)
{
# if defined(SHOW_EVERYTHING)
Test_Tell("Returning previously rejected token\n");
# endif
tokenNotTaken = False;
return currentToken;
}
char
*char_pointer = currentToken;
int
running,
c;
enum ParsingState
{
parsingWhiteSpace,
parsingToken,
parsingComment,
parsingString
};
ParsingState
parsingState = parsingWhiteSpace;
for(running=1; running; )
{
c = file.sgetc(); // check next character without pulling it
if ((char_pointer - currentToken) >= sizeof(currentToken))
{
Fail("Token too large");
return NULL;
}
if (c < 0)
{
if (char_pointer == currentToken)
{
# if defined(SHOW_EVERYTHING)
Test_Tell("EOF, NULL\n");
# endif
return NULL;
}
else
{
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("EOF, token=<" << currentToken << ">\n");
# endif
return currentToken;
}
}
if (c == '\n')
{
# if defined(SHOW_EVERYTHING)
Test_Tell("newline\n");
# endif
++lineNumber;
}
switch(parsingState)
{
case parsingWhiteSpace:
switch(c)
{
case ' ':
case '\t':
case '\r':
case '\n':
case '\0':
file.stossc(); // discard character
break;
case '#':
file.stossc(); // discard character
# if defined(SHOW_EVERYTHING)
Test_Tell("start comment\n");
# endif
parsingState = parsingComment;
break;
default:
# if defined(SHOW_EVERYTHING)
Test_Tell("non-white\n");
# endif
parsingState = parsingToken;
break;
}
break;
case parsingToken:
switch(c)
{
default:
file.stossc(); // discard character
*char_pointer++ = (char) c;
break;
case '"':
file.stossc(); // discard character
if (char_pointer == currentToken)
{
# if defined(SHOW_EVERYTHING)
Test_Tell("start string\n");
# endif
parsingState = parsingString;
}
else
{
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("start string, token=<" << currentToken << ">\n");
# endif
return currentToken;
}
break;
case '{':
case '}':
case '(':
case ')':
case ',':
case '=':
case ';':
if (char_pointer == currentToken)
{
file.stossc(); // discard character
*char_pointer++ = (char) c;
}
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("punctuation, token=<" << currentToken << ">\n");
# endif
return currentToken;
case '#':
file.stossc(); // discard character
# if defined(SHOW_EVERYTHING)
Test_Tell("start comment\n");
# endif
parsingState = parsingComment;
break;
case ' ':
case '\t':
case '\r':
case '\n':
case '\0':
file.stossc(); // discard character
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("trailing white, token=<" << currentToken << ">\n");
# endif
return currentToken;
}
break;
case parsingComment:
file.stossc(); // discard character
switch(c)
{
case '\n':
case '\r':
if (char_pointer == currentToken)
{
# if defined(SHOW_EVERYTHING)
Test_Tell("end of comment\n");
# endif
parsingState = parsingWhiteSpace;
}
else
{
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("end of comment, token=<" <<currentToken<< ">\n");
# endif
return currentToken;
}
break;
}
break;
case parsingString:
file.stossc(); // discard character
if (c == '"')
{
*char_pointer = '\0';
# if defined(SHOW_EVERYTHING)
Test_Tell("end of string, token=<" << currentToken << ">\n");
# endif
return currentToken;
}
else
{
*char_pointer++ = (char) c;
}
break;
}
}
Fail("Unintended exit");
Check_Fpu();
return NULL;
}
void
GaugeInterpreter::UngetPreviousToken()
{
Check(this);
tokenNotTaken = True;
Check_Fpu();
}
Logical
GaugeInterpreter::GetInteger(int *int_pointer)
{
Test_Tell(
"GaugeInterpreter::GetInteger(" << ((void *) int_pointer) <<
")..."
);
Check(this);
Check_Pointer(int_pointer);
const char
*token = GetToken();
Check_Pointer(token);
Test_Tell("token=" << token << "...");
int
c,
value = 0;
Logical
result,
is_negative = False;
if (*token == '-')
{
is_negative = True;
++token;
}
if (*token == '0')
{
++token;
if (*token == '\0')
{
Test_Tell("found zero value\n");
*int_pointer = 0;
return True;
}
}
if (*token == 'x' || *token == 'X')
{
for(++token; *token != '\0'; ++token)
{
c = toupper(*token);
if (!isxdigit(c))
{
return False;
}
if (c > '9')
{
c -= ('A'-':');
}
value = (value << 4) + (c - '0');
}
result = True;
}
else
{
for( ; *token != '\0'; ++token)
{
c = *token;
if (!isdigit(c))
{
return False;
}
value = (value*10) + (c - '0');
}
result = True;
}
if (result == True)
{
if (is_negative)
{
value = - value;
}
Test_Tell("found value " << value << "\n");
*int_pointer = value;
}
# if defined(LOCAL_TEST)
else
{
Test_Tell("FAILED\n");
}
# endif
Check_Fpu();
return result;
}
Logical
GaugeInterpreter::GetScalar(Scalar *scalar_pointer)
{
Test_Tell(
"GaugeInterpreter::GetScalar(" << ((void *) scalar_pointer) <<
")..."
);
Check(this);
Check_Pointer(scalar_pointer);
const char
*token = GetToken();
Check_Pointer(token);
Test_Tell("token=" << token << "\n");
float // HACK - I don't know how to avoid an explicit 'float'...
value;
Logical
is_negative = False;
if (*token == '-')
{
is_negative = True;
++token;
}
if (sscanf(token, "%f", &value) > 0)
{
Test_Tell("found " << value << "\n");
if (is_negative)
{
value = - value;
}
*scalar_pointer = (Scalar) value;
return True;
}
ReportParsingError("Token not a scalar value");
Check_Fpu();
return False;
}
Logical
GaugeInterpreter::GetVector(Vector2DOf<int> *vector)
{
Test_Tell("GaugeInterpreter::GetVector(" << ((void *) vector) << ")...");
Check(this);
Check_Pointer(vector);
Vector2DOf<int>
local_vector;
if (strcmp(GetToken(), "(") != 0)
{
ReportParsingError("Missing leading '(' for 2D vector");
return False;
}
if (!GetInteger(&local_vector.x))
{
return False;
}
if (strcmp(GetToken(), ",") != 0)
{
ReportParsingError("Missing ',' for 2D vector");
return False;
}
if (!GetInteger(&local_vector.y))
{
return False;
}
if (strcmp(GetToken(), ")") != 0)
{
ReportParsingError("Missing trailing ')' for 2D vector");
return False;
}
*vector = local_vector;
Check_Fpu();
return True;
}
Logical
GaugeInterpreter::GetRate(GaugeRate *rate)
{
Test_Tell("GaugeInterpreter::GetRate(" << ((void *) rate) << ")...");
Check(this);
const char
*text = GetToken();
Test_Tell("token='" << text << "'\n");
Check_Pointer(text);
Check_Pointer(rate);
int
c;
//-----------------------------------------------
// Get rate (A..P)
//-----------------------------------------------
c = *text;
if (!isalpha(c))
{
ReportParsingError("Token is not a valid rate");
}
else
{
c = toupper(c);
if ((c >= 'A') && (c <= 'Z'))
{
*rate = Gauge::ConvertIndexToRate(c -'A');
Check_Fpu();
return True;
}
else
{
ReportParsingError("Token is not a valid rate");
}
}
Check_Fpu();
return False;
}
Logical
GaugeInterpreter::GetModeMask(ModeMask *mask_pointer)
{
Test_Tell(
"GaugeInterpreter::GetLong(" << ((void *) mask_pointer) <<
")..."
);
Check(this);
Check_Pointer(mask_pointer);
const char
*token = GetToken();
Check_Pointer(token);
Test_Tell("token=" << token << "...");
int
c;
ModeMask
value = (ModeMask) 0;
Logical
result = False,
is_negative = False;
//------------------------------------------------------
// Deal with negative sign here
//------------------------------------------------------
if (*token == '-')
{
is_negative = True;
++token;
}
if (isalpha(*token))
{
//------------------------------------------------------
// Check for a named constant
//------------------------------------------------------
Check(application);
Check(application->GetModeManager());
result = application->GetModeManager()->ModeStringLookup(token, &value);
}
else
{
//--------------------------------------------------------
// Not a named constant. must be either number or an error
//--------------------------------------------------------
if (*token == '0')
{
++token;
result = True; // might be a single lonely zero (which is legit)
}
if (*token == 'x' || *token == 'X')
{
//--------------------------------------------------------
// Process hex value
//--------------------------------------------------------
for(++token; *token != '\0'; ++token)
{
c = toupper(*token);
if (!isxdigit(c))
{
return False;
}
if (c > '9')
{
c -= ('A'-':');
}
value = (value << 4) + (ModeMask) (c - '0');
}
result = True;
}
else
{
//--------------------------------------------------------
// Process decimal value
//--------------------------------------------------------
for( ; *token != '\0'; ++token)
{
c = *token;
if (!isdigit(c))
{
Check_Fpu();
return result;
}
value = (value*10) + (ModeMask) (c - '0');
}
result = True;
}
}
if (result == True)
{
if (is_negative)
{
value = - value;
}
Test_Tell("found value " << value << "\n");
*mask_pointer = value;
}
# if defined(LOCAL_TEST)
else
{
Test_Tell("FAILED\n");
}
# endif
Check_Fpu();
return result;
}
void
GaugeInterpreter::ReportParsingError(
const char *string
)
{
Check(this);
Check_Pointer(string);
DEBUG_STREAM <<
"Interpreter parsing error:" << string <<
" in line " << lineNumber <<
"\n";
Fail("Parsing error");
}
void
GaugeInterpreter::Initialize(
const char *file_name,
MethodDescription **method_list,
Warehouse *warehouse_pointer
)
{
Check(this);
Check_Pointer(file_name);
Check_Pointer(method_list);
Check(warehouse_pointer);
//------------------------------------------------------------------------
// Determine the number of primitives
//------------------------------------------------------------------------
MethodDescription
*method_entry,
**list;
primitiveCount = 0;
list = method_list;
while(list != NULL)
{
Check_Pointer(list);
method_entry = *list++;
Check_Pointer(method_entry);
if (method_entry->name == NULL)
{
//-------------------------------------------------------------
// Attempt to chain to next list: if NULL, we're done.
//-------------------------------------------------------------
list = method_entry->parameterList[0].data.nextMethodList;
}
else
{
//-------------------------------------------------------------
// Increment the primitive count
//-------------------------------------------------------------
++primitiveCount;
}
}
//------------------------------------------------------------------------
// Allocate the primitive table
//------------------------------------------------------------------------
primitiveTable = new MethodDescription*[primitiveCount];
Register_Pointer(primitiveTable);
//------------------------------------------------------------------------
// Fill in the primitiveTable
//------------------------------------------------------------------------
MethodDescription
**method_pointer = primitiveTable;
list = method_list;
while(list != NULL)
{
Check_Pointer(list);
method_entry = *list++;
Check_Pointer(method_entry);
if (method_entry->name == NULL)
{
//-------------------------------------------------------------
// Attempt to chain to next list: if NULL, we're done.
//-------------------------------------------------------------
list = method_entry->parameterList[0].data.nextMethodList;
}
else
{
//-------------------------------------------------------------
// Save a pointer to the method description
//-------------------------------------------------------------
Verify((method_pointer-primitiveTable) < primitiveCount);
*(method_pointer++) = method_entry;
}
}
//------------------------------------------------------------------------
// Parse the text file to build the interpreter table
//------------------------------------------------------------------------
//file.open(file_name, std::ios::in|std::ios::nocreate, std::filebuf::openprot);
// alternate line added by RB 1/6/2007
file.open(file_name, std::ios::in, std::ios::_Openprot);
if (!file.is_open())
{
DEBUG_STREAM << "Cannot open interpreter file '" << file_name << "'\n" << std::flush;
}
else
{
lineNumber = 1;
tokenNotTaken = False;
const char
*name;
char
local_name[32];
//----------------------------------------------------
// Parse the statement:
// <name> { <body> }
//----------------------------------------------------
//
while((name = GetToken()) != NULL )
{
Str_Copy(local_name, name, sizeof(local_name));
if (stricmp(GetToken(), "{") != 0)
{
ReportParsingError("Missing '{'");
}
symbolTable->Add(local_name, currentOffset);
GetProcedureBody(method_list, warehouse_pointer);
}
if (symbolTable->UnresolvedForwardReferences())
{
ReportParsingError("Unresolved forward references");
}
file.close();
{
GaugeInterpreterCommand
command = endMarker;
Insert(&command, sizeof(GaugeInterpreterCommand));
# if defined(LOCAL_TEST)
DumpTable();
# endif
};
}
//------------------------------------------------------------------------
// All done!
//------------------------------------------------------------------------
Check_Fpu();
}
void
GaugeInterpreter::GetProcedureBody(
MethodDescription **method_list,
Warehouse *warehouse_pointer
)
{
Check(this);
Check_Pointer(method_list);
Check(warehouse_pointer);
int
running = 1;
GaugeInterpreterCommand
command;
const char
*name;
char
local_name[32];
while (running)
{
name = GetToken();
if (name == NULL)
{
ReportParsingError("Internal error (NULL token)");
}
Str_Copy(local_name, name, sizeof(local_name));
if (stricmp(name, "}") == 0)
{
Test_Tell("End\n");
command = returnCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
break;
}
else if (*name == '@') // example: @1 = ppc/reloadtime;
{
if (strlen(name) != 2)
{
ReportParsingError("Ill-formed attribute variable index");
}
unsigned char
index = (unsigned char) ((*(name+1)) - '0');
if (index > maxVariableNameArrayIndex)
{
ReportParsingError("Illegal attribute variable index");
}
if (strcmp(GetToken(), "=") != 0)
{
ReportParsingError("Missing '='");
}
Test_Tell("Attribute variable\n");
command = attributeVariableCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
Insert(&index, sizeof(unsigned char));
InsertString(GetToken());
}
else if (stricmp(name, "enable") == 0)
{
if (strcmp(GetToken(), "=") != 0)
{
ReportParsingError("Missing '='");
}
ModeMask
mode_mask;
GetModeMask(&mode_mask); // fails to debugger if bad input
Test_Tell("Enable\n");
command = enableCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
Insert(&mode_mask, sizeof(ModeMask));
}
else if (stricmp(name, "disable") == 0)
{
if (strcmp(GetToken(), "=") != 0)
{
ReportParsingError("Missing '='");
}
ModeMask
mode_mask;
GetModeMask(&mode_mask); // fails to debugger if bad input
Test_Tell("Disable\n");
command = disableCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
Insert(&mode_mask, sizeof(ModeMask));
}
else if (stricmp(name, "offset") == 0)
{
if (strcmp(GetToken(), "=") != 0)
{
ReportParsingError("Missing '='");
}
Vector2DOf<int>
offset;
GetVector(&offset); // fails to debugger if input bad
Test_Tell("offset\n");
command = addOffsetCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
Insert(&offset, sizeof(Vector2DOf<int>));
}
else if (stricmp(name, "port") == 0)
{
if (strcmp(GetToken(), "=") != 0)
{
ReportParsingError("Missing '='");
}
command = setPortIndexCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
InsertString(GetToken());
}
else // must be either call or primitive
{
const char
*token = GetToken();
if (stricmp(token, "(") == 0)
{
if (
ParsePrimitive(
local_name,
method_list,
warehouse_pointer
) == False
)
{
//
// BT DEV-GAUGES bring-up: the BT-specific gauge primitive
// table (BTL4MethodDescription, btl4grnd.cpp) is still a stub
// -- the BT gauge widget classes (PlayerStatus, ...) aren't
// reconstructed yet, so they don't resolve here. Rather than
// Fail() -- which pops a modal assert dialog and FREEZES the
// game mid-parse -- SKIP the unknown primitive's parameter
// list so the parse can continue: it still registers every
// label (e.g. Bhk1Init -> MechInit) and runs the base
// "configure" primitives that build the gauge PORTS/surfaces
// (the beachhead needs the 'sec'/radar surface, not the
// widgets). Gated on BT_DEV_GAUGES so the POD path keeps the
// strict Fail (it needs a complete, real method table).
//
if (getenv("BT_DEV_GAUGES") != NULL)
{
const char
*skip_token;
int
paren_depth = 1; // the '(' already consumed above
while (
(paren_depth > 0) &&
((skip_token = GetToken()) != NULL)
)
{
if (stricmp(skip_token, "(") == 0)
++paren_depth;
else if (stricmp(skip_token, ")") == 0)
--paren_depth;
}
UngetPreviousToken(); // leave ')' for the check below
}
else
{
ReportParsingError("Undefined primitive");
}
}
if (stricmp(GetToken(), ")") != 0)
{
ReportParsingError("Missing ')'");
}
}
else
{
UngetPreviousToken();
Test_Tell("Call to '" << local_name << "'\n");
command = callCommand;
Insert(&command, sizeof(GaugeInterpreterCommand));
Check(symbolTable);
GaugeInterpreterOffset
offset = symbolTable->Refer(local_name, currentOffset);
Insert(&offset, sizeof(GaugeInterpreterOffset));
}
}
if (stricmp(GetToken(), ";") != 0)
{
ReportParsingError("Missing ';'");
}
}
Check_Fpu();
}
Logical
GaugeInterpreter::ParsePrimitive(
const char *name,
MethodDescription **method_list,
Warehouse *warehouse_pointer
)
{
Test_Tell(
"GaugeInterpreter::ParsePrimitive(" << name <<
", " << method_list <<
", " << warehouse_pointer <<
")\n"
);
Check(this);
Check_Pointer(name);
Check_Pointer(method_list);
Check(warehouse_pointer);
MethodDescription
*method_entry,
**list;
GaugeInterpreterCommand
command_number = nextAvailableCommand;
int
i;
Logical
first_parameter = True;
list = method_list;
while(list != NULL)
{
Check_Pointer(list);
method_entry = *list++;
Check_Pointer(method_entry);
if (method_entry->name == NULL)
{
//-------------------------------------------------------------
// Attempt to chain to next list: if NULL, we didn't match.
//-------------------------------------------------------------
list = method_entry->parameterList[0].data.nextMethodList;
}
else
{
//-------------------------------------------------------------
// Attempt to match this entry
//-------------------------------------------------------------
Test_Tell("<" << method_entry->name << ">\n");
if (stricmp(method_entry->name, name) != 0)
{
command_number = (GaugeInterpreterCommand) (command_number + 1);
}
else
{
//-------------------------------------------------------
// Name found, attempt to procure parameters
//-------------------------------------------------------
Test_Tell("Found, attempt to match parameters\n");
for (
i=0;
method_entry->parameterList[i].type !=
ParameterDescription::typeEmpty;
++i
)
{
//-------------------------------------------------------
// Eat commas (after first parameter)
//-------------------------------------------------------
if (first_parameter)
{
first_parameter = False;
}
else
{
if (stricmp(GetToken(), ",") != 0)
{
ReportParsingError("Missing ','");
return False;
}
}
//-------------------------------------------------------
// Read a parameter
//-------------------------------------------------------
if (method_entry->parameterList[i].
Extract(this, warehouse_pointer) == False
)
{
//----------------------------------------------
// Not found, error
//----------------------------------------------
ReportParsingError("Wrong or missing parameter");
return False;
}
}
//-------------------------------------------------------
// All parameters found, write to the interpreter table
//-------------------------------------------------------
Test_Tell("All parameters matched\n");
Check_Pointer(method_entry->execute); // make sure it's executable
Verify((command_number-nextAvailableCommand) >= 0);
Verify((command_number-nextAvailableCommand) < primitiveCount);
Insert(&command_number, sizeof(GaugeInterpreterCommand));
for (
i=0;
method_entry->parameterList[i].type !=
ParameterDescription::typeEmpty;
++i
)
{
method_entry->parameterList[i].Save(this);
}
Test_Tell("All done\n");
Check_Fpu();
return True;
}
}
}
//-------------------------------------------------------------
// Name not matched, return error
//-------------------------------------------------------------
Test_Tell("Not found!\n");
Check_Fpu();
return False;
}
void
GaugeInterpreter::Insert(const void *value_pointer, int size_in_chars)
{
# if defined(SHOW_EVERYTHING)
Test_Tell(
"GaugeInterpreter::Insert(" << ((void *) value_pointer) <<
"," << size_in_chars <<
")\n"
);
# endif
Check(this);
Check_Pointer(value_pointer);
Verify(size_in_chars > 0);
Verify((currentOffset+size_in_chars) < interpreterTableSize);
char
*source;
for(
source= (char *) value_pointer;
size_in_chars!=0;
++source, --size_in_chars
)
{
interpreterTable[currentOffset++] = *source;
}
Check_Fpu();
}
void *
GaugeInterpreter::Retrieve(int size_in_chars)
{
# if defined(SHOW_EVERYTHING)
Test_Tell(
"GaugeInterpreter::Retrieve(" << size_in_chars << ")\n"
);
# endif
Check(this);
Verify(size_in_chars > 0);
Verify(currentOffset >= 0);
Verify(currentOffset < interpreterTableSize);
void
*here = &interpreterTable[currentOffset];
currentOffset = (GaugeInterpreterOffset) (currentOffset + size_in_chars);
Verify(currentOffset < interpreterTableSize);
Check_Fpu();
return here;
}
void
GaugeInterpreter::InsertString(const char *string)
{
Check(this);
Check_Pointer(string);
unsigned short
length = (unsigned short) (strlen(string)+1);
Test_Tell(
"GaugeInterpreter::InsertString(" << string <<
"), len=" << length << "\n"
);
Verify(length < ParameterDescription::maxStringLength);
Insert(&length, sizeof(unsigned short));
Insert(string, length);
Check_Fpu();
}
const char *
GaugeInterpreter::RetrieveString()
{
# if defined(SHOW_EVERYTHING)
Test_Tell(
"GaugeInterpreter::RetrieveString()='"
);
# endif
Check(this);
const char
*pointer;
unsigned short
length = *(unsigned short *) Retrieve(sizeof(unsigned short));
Verify(length < ParameterDescription::maxStringLength);
pointer = (const char *) &interpreterTable[currentOffset];
Check_Pointer(pointer);
currentOffset = (GaugeInterpreterOffset) (currentOffset + length);
# if defined(SHOW_EVERYTHING)
Test_Tell( pointer << "', len=" << length << "\n");
# endif
Check_Fpu();
return pointer;
}
void
GaugeInterpreter::Interpret(
const char *label,
GaugeRenderer *renderer,
int display_port_index,
Vector2DOf<int> position,
Entity *entity
)
{
Test_Tell(
"GaugeInterpreter::Interpret('" << label <<
"'," << renderer <<
"," << display_port_index <<
"," << position <<
"," << entity <<
"\n"
);
Check(this);
Check_Pointer(label);
Check(renderer);
// 'entity' is allowed to be NULL
Check(symbolTable);
Check_Pointer(interpreterTable);
GaugeInterpreterOffset
offset = symbolTable->Get(label);
if (offset < 0)
{
DEBUG_STREAM << "GaugeInterpreter: undefined label '" << label << "'\n" << std::flush;
}
else
{
InterpretFromOffset(
offset,
renderer,
display_port_index,
position,
entity
);
}
Check_Fpu();
}
void
GaugeInterpreter::InterpretFromOffset(
GaugeInterpreterOffset offset,
GaugeRenderer *renderer,
int display_port_index,
Vector2DOf<int> original_position,
Entity *entity
)
{
Test_Tell(
"GaugeInterpreter::InterpretFromOffset(" << offset <<
"," << renderer <<
"," << display_port_index <<
"," << original_position <<
"," << entity <<
"\n"
);
Check(this);
Check(renderer);
Verify(offset >= 0);
// 'entity' is allowed to be NULL
Check_Pointer(interpreterTable);
currentOffset = offset;
GaugeInterpreterCommand
command;
int
running = 1;
Vector2DOf<int>
position;
position = original_position;
while(running)
{
command = *(GaugeInterpreterCommand *)
Retrieve(sizeof(GaugeInterpreterCommand));
switch(command)
{
case endMarker:
case returnCommand:
Test_Tell("Return\n");
running = 0;
break;
case setPortIndexCommand:
{
const char
*port_name = RetrieveString();
Test_Tell("Set port=" << port_name << "\n");
//------------------------------------------
// Replace variable if needed
//------------------------------------------
port_name = ReplaceVariable(port_name);
int
port = renderer->FindGraphicsPort(port_name);
if (port >= 0)
{
display_port_index = port;
}
else
{
Tell(
"GaugeInterpreter::InterpretFromOffset: port '"<<
port_name << "' not found!\n"
);
}
}
break;
case addOffsetCommand:
{
Vector2DOf<int>
temp;
temp = *(Vector2DOf<int> *) Retrieve(sizeof(Vector2DOf<int>));
Test_Tell("Add offset " << std::dec << temp);
position.x = original_position.x + temp.x;
position.y = original_position.y + temp.y;
Test_Tell(" to " << position << "\n");
}
break;
case attributeVariableCommand:
{
unsigned char
index = *(unsigned char *)Retrieve(sizeof(unsigned char));
const char
*attribute_name = RetrieveString();
Test_Tell(
"attribute variable #" << index << "=" << attribute_name << "\n"
);
Verify(index < maxVariableNameArrayIndex);
attributeNameArray[index] = attribute_name;
}
break;
case callCommand:
{
GaugeInterpreterOffset
new_offset =
*(GaugeInterpreterOffset *)
Retrieve(sizeof(GaugeInterpreterOffset));
Test_Tell("Call " << std::hex << new_offset << std::dec << "\n");
offset = currentOffset; // save for call
InterpretFromOffset(
new_offset,
renderer,
display_port_index,
position,
entity
);
currentOffset = offset; // restore offset
}
break;
case enableCommand:
Test_Tell("Enable\n");
{
Check(application);
Check(application->GetModeManager());
application->GetModeManager()->AddModeMask(
*(ModeMask*)Retrieve(sizeof(ModeMask))
);
}
break;
case disableCommand:
Test_Tell("Disable\n");
{
Check(application);
Check(application->GetModeManager());
application->GetModeManager()->RemoveModeMask(
*(ModeMask*)Retrieve(sizeof(ModeMask))
);
}
break;
default:
command = (GaugeInterpreterCommand) (command - nextAvailableCommand);
Verify(command < primitiveCount);
Check_Pointer(primitiveTable);
Test_Tell("****" << primitiveTable[command]->name<< "\n");
primitiveTable[command]->Execute(
display_port_index,
position,
entity,
renderer
);
break;
}
}
Check_Fpu();
}
const char *
GaugeInterpreter::ReplaceVariable(const char *string)
{
Check(this);
Verify(string != NULL);
if (*string == '@')
{
unsigned char
index = *(string+1);
if ((index >= '0') && (index <= '9'))
{
string = attributeNameArray[index - '0'];
Verify(string != NULL);
Test_Tell(
"Variable @" << index << " replaced with '" << string <<"'\n"
);
}
}
Check_Fpu();
return string;
}
void
GaugeInterpreter::DumpTable()
{
Test_Tell("GaugeInterpreter::DumpTable\n");
Check(this);
GaugeInterpreterCommand
command;
const char
*label;
currentOffset = 0;
do
{
label = symbolTable->LabelFromValue(currentOffset);
if (label != NULL)
{
DEBUG_STREAM << label << ":\n" << std::flush;
}
DEBUG_STREAM << " " << std::hex << currentOffset << ":" << std::flush;
command = *(GaugeInterpreterCommand *)
Retrieve(sizeof(GaugeInterpreterCommand));
switch(command)
{
case endMarker:
DEBUG_STREAM << "---------End of table---------\n" << std::flush;
break;
case returnCommand:
DEBUG_STREAM <<"return\n" << std::flush;
break;
case setPortIndexCommand:
{
const char
*port_name = RetrieveString();
DEBUG_STREAM << "setport '" << port_name << "'\n" << std::flush;
}
break;
case addOffsetCommand:
{
Vector2DOf<int>
offset = *(Vector2DOf<int> *) Retrieve(sizeof(Vector2DOf<int>));
DEBUG_STREAM << "offset " << std::dec << offset << "\n" << std::flush;
}
break;
case callCommand:
{
GaugeInterpreterOffset
new_offset =
*(GaugeInterpreterOffset *)
Retrieve(sizeof(GaugeInterpreterOffset));
DEBUG_STREAM << "call 0x" << new_offset << " (" << std::flush;
const char
*name = symbolTable->LabelFromValue(new_offset);
if (name == NULL)
{
DEBUG_STREAM << "UNDEFINED!!!)\n" << std::flush;
}
else
{
DEBUG_STREAM << name << ")\n" << std::flush;
}
}
break;
case enableCommand:
{
ModeMask
mask = *(ModeMask*)Retrieve(sizeof(ModeMask));
DEBUG_STREAM << "enable 0x" << mask << "\n" << std::flush;
}
break;
case disableCommand:
{
ModeMask
mask = *(ModeMask*)Retrieve(sizeof(ModeMask));
DEBUG_STREAM << "disable 0x" << mask << "\n" << std::flush;
}
break;
default:
{
MethodDescription
*method_entry = primitiveTable[command-nextAvailableCommand];
DEBUG_STREAM << method_entry->name << ":\n" << std::flush;
int
i;
for (
i=0;
method_entry->parameterList[i].type !=
ParameterDescription::typeEmpty;
++i
)
{
//-------------------------------------------------------
// Show a parameter
//-------------------------------------------------------
method_entry->parameterList[i].DumpInterpreterEntry(
this,
" "
);
}
}
break;
}
}
while(command != endMarker);
Check_Fpu();
}
//#############################################################################
// ParameterDescription
//#############################################################################
ParameterDescription::~ParameterDescription()
{
Check_Fpu();
}
#if DEBUG_LEVEL <= 0
void
ParameterDescription::CheckIt(int /*this_type*/)
{
}
#else
void
ParameterDescription::CheckIt(int this_type)
{
Check_Pointer(this);
Verify(type == this_type);
switch(type)
{
case typeEmpty:
case typeRate:
case typeModeMask:
case typeInteger:
case typeColor:
case typeScalar:
case typeVector:
case typeRectangle:
break;
case typeAttribute:
case typeString:
if (data.string != NULL)
{
Check_Pointer(data.string);
}
break;
default:
Fail("Illegal parameter type!");
}
Check_Fpu();
}
#endif
void
ParameterDescription::ShowInstance(
char *indent
)
{
Check_Pointer(this);
DEBUG_STREAM << indent << "ParameterDescription:" << std::dec << std::flush;
switch(type)
{
case typeEmpty:
DEBUG_STREAM << "empty" << std::flush;
break;
case typeRate:
DEBUG_STREAM << "rate=" << std::flush;
{
int
i,j;
for(i='A',j=0x10000; i<'Q'; ++i, j<<=1)
{
if (data.rate & j)
{
DEBUG_STREAM << (char) i << std::flush;
}
}
}
break;
case typeModeMask:
DEBUG_STREAM << std::hex << "modeMask=" << data.modeMask << std::dec << std::flush;
break;
case typeInteger:
DEBUG_STREAM << "integer=" << data.integer << std::flush;
break;
case typeColor:
DEBUG_STREAM << "color=0x" << std::hex << data.color << std::dec << std::flush;
break;
case typeScalar:
DEBUG_STREAM << "scalar=" << data.scalar << std::flush;
break;
case typeVector:
DEBUG_STREAM <<
"vector= (" << data.vector.x <<
", " << data.vector.y <<
")";
break;
case typeRectangle:
DEBUG_STREAM <<
"rectangle= ((" << data.rectangle.bottomLeft.x <<
", " << data.rectangle.bottomLeft.y <<
"),(" << data.rectangle.topRight.x <<
", " << data.rectangle.topRight.y <<
")";
break;
case typeAttribute:
if (data.string == NULL)
{
DEBUG_STREAM << "attribute=NULL\n" << std::flush;
}
else
{
DEBUG_STREAM << "attribute=<" << data.string << ">" << std::flush;
}
break;
case typeString:
if (data.string == NULL)
{
DEBUG_STREAM << "string=NULL\n" << std::flush;
}
else
{
DEBUG_STREAM << "string=<" << data.string << ">" << std::flush;
}
break;
default:
DEBUG_STREAM << "ILLEGAL TYPE=" << type << std::flush;
}
DEBUG_STREAM << "\n" << std::flush;
Check_Fpu();
}
void *
ParameterDescription::ParseAttribute(
const char *string_pointer,
Entity *entity
)
{
Test_Tell(
"ParameterDescription::ParseAttribute('" << string_pointer <<
"', " << entity <<
")\n"
);
Check_Pointer(this);
Check_Pointer(string_pointer);
Check(entity);
Simulation*
simulation;
char
temp_string[80],
*source,
*temp_ptr;
Verify(type == typeAttribute);
Str_Copy(temp_string, string_pointer, sizeof(temp_string));
source = temp_string;
for(temp_ptr = source; *temp_ptr != '\0'; ++temp_ptr)
{
if (*temp_ptr == '/')
{
*temp_ptr = '\0';
Test_Tell("Subsystem name=" << source << "\n");
simulation = (Simulation *) entity->FindSubsystem(source);
if (simulation == NULL)
{
Tell("parseAttribute - subsystem '" << source << "' not found\n");
Check_Fpu();
return NULL;
}
else
{
source = temp_ptr+1;
Test_Tell("Subsystem attribute name=" << source << "\n");
void
*attribute_pointer = simulation->GetAttributePointer(source);
if (attribute_pointer == NULL)
{
Tell(
"parseAttribute - attribute '" <<
string_pointer << "' not found\n"
);
}
// gauge data-binding wave: a per-binding resolution trace to the
// log file (env BT_GAUGE_ATTR_LOG) -- proves which cockpit bindings
// resolve to a live member vs read NULL (unpublished attribute).
if (getenv("BT_GAUGE_ATTR_LOG"))
DEBUG_STREAM << "[attr] " << string_pointer
<< (attribute_pointer ? " OK\n" : " NULL\n") << std::flush;
Check_Fpu();
return attribute_pointer;
}
}
}
Test_Tell("Entity attribute name=" << source << "\n");
void
*attribute_pointer = ((Simulation *)entity)->GetAttributePointer(source);
if (attribute_pointer == NULL)
{
Tell(
"parseAttribute - attribute '" <<
source << "' not found\n"
);
}
if (getenv("BT_GAUGE_ATTR_LOG"))
DEBUG_STREAM << "[attr] " << source
<< (attribute_pointer ? " OK (entity)\n" : " NULL (entity)\n") << std::flush;
Check_Fpu();
return attribute_pointer;
}
Logical
ParameterDescription::Extract(
GaugeInterpreter *interpreter,
Warehouse *warehouse_pointer
)
{
Test_Tell(
"ParameterDescription::Extract(" << interpreter <<
", " << warehouse_pointer <<
")\n"
);
Check_Pointer(this);
Check(interpreter);
//
//----------------------------------------------------------------
// Choose the appropriate parameter type, attempt to create it
//----------------------------------------------------------------
//
switch(type)
{
case typeEmpty:
Fail("type == empty!");
break;
case typeRate:
Test_Tell("rate? ");
if (interpreter->GetRate(&data.rate))
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
break;
case typeModeMask:
Test_Tell("modeMask? ");
if (interpreter->GetModeMask(&data.modeMask))
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
break;
case typeInteger:
Test_Tell("integer? ");
if (interpreter->GetInteger(&data.integer))
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
break;
case typeColor:
Test_Tell("color? ");
if (interpreter->GetInteger(&data.color))
{
if (data.color <= 0xFF && data.color >= 0)
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
}
break;
case typeScalar:
Test_Tell("scalar? ");
if (interpreter->GetScalar(&data.scalar))
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
break;
case typeVector:
Test_Tell("vector? ");
{
Vector2DOf<int>
temp_vector;
if (interpreter->GetVector(&temp_vector))
{
data.vector.x = temp_vector.x;
data.vector.y = temp_vector.y;
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
}
break;
case typeRectangle:
Test_Tell("rectangle? ");
{
int
success;
success = (strcmp(interpreter->GetToken(), "(") == 0);
success &= interpreter->GetInteger(&data.rectangle.bottomLeft.x);
success &= (strcmp(interpreter->GetToken(), ",") == 0);
success &= interpreter->GetInteger(&data.rectangle.bottomLeft.y);
success &= (strcmp(interpreter->GetToken(), ",") == 0);
success &= interpreter->GetInteger(&data.rectangle.topRight.x);
success &= (strcmp(interpreter->GetToken(), ",") == 0);
success &= interpreter->GetInteger(&data.rectangle.topRight.y);
success &= (strcmp(interpreter->GetToken(), ")") == 0);
if (success)
{
Test_Tell("yes.\n");
Check_Fpu();
return True;
}
}
break;
case typeAttribute:
{
const char
*token = interpreter->GetToken();
Test_Tell("attribute='");
Str_Copy(data.string, token, maxStringLength-1);
Test_Tell(data.string << "'\n");
Check_Fpu();
}
return True;
case typeString:
{
const char
*token = interpreter->GetToken();
Test_Tell("string='");
Str_Copy(data.string, token, maxStringLength-1);
Test_Tell(data.string << "'\n");
Check_Fpu();
}
return True;
default:
Fail("Illegal type");
return False;
}
Test_Tell("NO!\n");
Check_Fpu();
return False;
}
void
ParameterDescription::Save(GaugeInterpreter *interpreter)
{
Test_Tell("ParameterDescription::Save(" << interpreter << ")\n");
Check_Pointer(this);
Check(interpreter);
//
//----------------------------------------------------------------
// Choose the appropriate type, write to interpreter table
//----------------------------------------------------------------
//
switch(type)
{
case typeEmpty:
Fail("type == empty!");
break;
case typeRate:
Test_Tell("rate\n");
interpreter->Insert(&data.rate, sizeof(GaugeRate));
break;
case typeModeMask:
Test_Tell("modeMask\n");
interpreter->Insert(&data.modeMask, sizeof(ModeMask));
break;
case typeInteger:
Test_Tell("integer\n");
interpreter->Insert(&data.integer, sizeof(int));
break;
case typeColor:
Test_Tell("color\n");
interpreter->Insert(&data.color, sizeof(int));
break;
case typeScalar:
Test_Tell("scalar\n");
interpreter->Insert(&data.scalar, sizeof(Scalar));
break;
case typeVector:
Test_Tell("vector\n");
interpreter->Insert(&data.vector.x, sizeof(int));
interpreter->Insert(&data.vector.y, sizeof(int));
break;
case typeRectangle:
Test_Tell("rectangle\n");
interpreter->Insert(&data.rectangle.bottomLeft.x, sizeof(int));
interpreter->Insert(&data.rectangle.bottomLeft.y, sizeof(int));
interpreter->Insert(&data.rectangle.topRight.x, sizeof(int));
interpreter->Insert(&data.rectangle.topRight.y, sizeof(int));
break;
case typeAttribute:
Test_Tell("attribute\n");
Check_Pointer(data.string);
interpreter->InsertString(data.string);
break;
case typeString:
Test_Tell("string\n");
interpreter->InsertString(data.string);
break;
default:
Fail("Illegal type");
break;
}
Check_Fpu();
}
void
ParameterDescription::Restore(
GaugeInterpreter *interpreter,
Entity *entity
)
{
Check_Pointer(this);
Check(interpreter);
Test_Tell("\nParameterDescription::Restore-");
//
//----------------------------------------------------------------
// Choose the appropriate type, read from interpreter table
//----------------------------------------------------------------
//
switch(type)
{
case typeEmpty:
Fail("type == empty!");
break;
case typeRate:
data.rate = *(GaugeRate *)interpreter->Retrieve(sizeof(GaugeRate));
Test_Tell("rate=" << std::hex << data.rate << std::dec << "\n");
break;
case typeModeMask:
data.modeMask = *(ModeMask *)
interpreter->Retrieve(sizeof(ModeMask));
Test_Tell("modeMask=" << std::hex << data.modeMask << std::dec << "\n");
break;
case typeInteger:
data.integer = *(int *) (interpreter->Retrieve(sizeof(int)));
Test_Tell("integer=" << data.integer << "\n");
break;
case typeColor:
data.color = *(int *) (interpreter->Retrieve(sizeof(int)));
Test_Tell("color=" << data.color << "\n");
break;
case typeScalar:
data.scalar = *(Scalar *) (interpreter->Retrieve(sizeof(Scalar)));
Test_Tell("scalar=" << data.scalar << "\n");
break;
case typeVector:
data.vector.x = *(int*) interpreter->Retrieve(sizeof(int));
data.vector.y = *(int*) interpreter->Retrieve(sizeof(int));
Test_Tell("vector=(" << data.vector.x << "," << data.vector.y << ")\n");
break;
case typeRectangle:
data.rectangle.bottomLeft.x = *(int*) interpreter->Retrieve(sizeof(int));
data.rectangle.bottomLeft.y = *(int*) interpreter->Retrieve(sizeof(int));
data.rectangle.topRight.x = *(int*) interpreter->Retrieve(sizeof(int));
data.rectangle.topRight.y = *(int*) interpreter->Retrieve(sizeof(int));
Test_Tell(
"rectangle=((" << data.rectangle.bottomLeft.x <<
"," << data.rectangle.bottomLeft.y <<
"),(" << data.rectangle.topRight.x <<
"," << data.rectangle.topRight.y <<
"))\n"
);
break;
case typeAttribute:
{
const char
*string_pointer = interpreter->RetrieveString();
Verify(string_pointer != NULL);
Test_Tell("attribute=" << string_pointer << "\n");
//--------------------------------------
// Replace if variable name
//--------------------------------------
string_pointer = interpreter->ReplaceVariable(string_pointer);
//--------------------------------------
// Change into true attribute pointer
//--------------------------------------
Check(entity);
data.attributePointer = ParseAttribute(string_pointer, entity);
Verify(data.attributePointer != NULL);
}
break;
case typeString:
Test_Tell("string\n");
{
// Get the string here INSTEAD of inside Str_Copy() because
// of side effects! (string_pointer is referenced multiple times)
const char
*string_pointer = interpreter->RetrieveString();
//--------------------------------------
// Replace if variable name
//--------------------------------------
string_pointer = interpreter->ReplaceVariable(string_pointer);
Test_Tell("string=" << string_pointer << "\n");
Str_Copy(
data.string,
string_pointer,
maxStringLength-1
);
}
break;
default:
Fail("Illegal type");
break;
}
Check_Fpu();
}
void
ParameterDescription::DumpInterpreterEntry(
GaugeInterpreter *interpreter,
const char *indent
)
{
Check_Pointer(this);
Check(interpreter);
//----------------------------------------------------------------
// Choose the appropriate type, read from interpreter table
//----------------------------------------------------------------
DEBUG_STREAM << indent << std::flush;
switch(type)
{
case typeEmpty:
DEBUG_STREAM << "***EMPTY***\n" << std::flush;
break;
case typeRate:
{
GaugeRate
rate = *(GaugeRate *)
interpreter->Retrieve(sizeof(GaugeRate));
DEBUG_STREAM << "rate " << rate << "\n" << std::flush;
}
break;
case typeModeMask:
{
ModeMask
mask = *(ModeMask *)
interpreter->Retrieve(sizeof(ModeMask));
DEBUG_STREAM << "mask " << mask << "\n" << std::flush;
}
break;
case typeInteger:
{
int
i = *(int *) (interpreter->Retrieve(sizeof(int)));
DEBUG_STREAM << std::dec << "int " << i << "\n" << std::flush;
}
break;
case typeColor:
{
int
i = *(int *) (interpreter->Retrieve(sizeof(int)));
DEBUG_STREAM << "color 0x" << i << "\n" << std::flush;
}
break;
case typeScalar:
{
Scalar
s = *(int *) (interpreter->Retrieve(sizeof(Scalar)));
DEBUG_STREAM << std::dec << "scalar " << s << "\n" << std::flush;
}
break;
case typeVector:
{
Vector2DOf<int>
v;
v.x = *(int *) (interpreter->Retrieve(sizeof(int)));
v.y = *(int *) (interpreter->Retrieve(sizeof(int)));
DEBUG_STREAM << std::dec << "vector " << v << "\n" << std::flush;
}
break;
case typeRectangle:
{
Rectangle2D
r;
r.bottomLeft.x = *(int *) (interpreter->Retrieve(sizeof(int)));
r.bottomLeft.y = *(int *) (interpreter->Retrieve(sizeof(int)));
r.topRight.x = *(int *) (interpreter->Retrieve(sizeof(int)));
r.topRight.y = *(int *) (interpreter->Retrieve(sizeof(int)));
DEBUG_STREAM << std::dec << "rectangle " << r << "\n" << std::flush;
}
break;
case typeAttribute:
DEBUG_STREAM << "attribute '" << interpreter->RetrieveString() << "'\n" << std::flush;
break;
case typeString:
DEBUG_STREAM << "string '" << interpreter->RetrieveString() << "'\n" << std::flush;
break;
default:
DEBUG_STREAM << "ILLEGAL TYPE=" << type << "!!\n" << std::flush;
break;
}
Check_Fpu();
}
//#############################################################################
// MethodDescription
//#############################################################################
void
MethodDescription::ShowInstance(char *indent)
{
Check_Pointer(this);
DEBUG_STREAM << indent << "MethodDescription:\n" << std::flush;
char
temp[80];
int
i;
DEBUG_STREAM << indent << "name =" << name << "\n" << std::flush;
DEBUG_STREAM << indent << "execute=" << execute << "\n" << std::flush;
for(i=0; i<MaximumParameters; ++i)
{
if (parameterList[i].type == ParameterDescription::typeEmpty)
{
break;
}
Verify(strlen(indent)+2 < 80);
sprintf(temp,"%s%2d:", indent, i);
parameterList[i].ShowInstance(temp);
}
Check_Fpu();
}
void
MethodDescription::Execute(
int display_port_index,
Vector2DOf<int> position,
Entity *entity,
GaugeRenderer *renderer
)
{
Check_Pointer(this);
Check(renderer);
Check(renderer->interpreter);
int
i;
//-------------------------------------------------------------
// Restore the parameters from the interpreter table
//-------------------------------------------------------------
for (i=0; parameterList[i].type != ParameterDescription::typeEmpty; ++i)
{
parameterList[i].Restore(renderer->interpreter, entity);
}
//-------------------------------------------------------------
// Execute the call
//-------------------------------------------------------------
Check_Pointer(execute);
# if DEBUG_LEVEL > 0
Logical
result =
(*execute)(
display_port_index,
position,
entity,
renderer
);
Verify(result == True);
# else
(*execute)(
display_port_index,
position,
entity,
renderer
);
# endif
Check_Fpu();
}
//#######################################################################
// GaugeRendererStatistics
//#######################################################################
void
GaugeRendererStatistics::Clear()
{
sampleCount = 0;
sum = (Scalar) 0;
maximum = (Scalar) 0;
Check_Fpu();
}
void
GaugeRendererStatistics::Update(Scalar delta)
{
++sampleCount;
sum += delta;
if (maximum < delta)
{
maximum = delta;
}
Check_Fpu();
}
Scalar
GaugeRendererStatistics::CalculateAverage()
{
Scalar
average;
if (sampleCount <= 0)
{
average = (Scalar) 0;
}
else
{
average = (Scalar) (sum/sampleCount);
}
Check_Fpu();
return average;
}
//#############################################################################
// GaugeRenderer
//#############################################################################
GaugeRenderer
*GaugeRenderer::headGaugeRenderer = NULL;
GaugeRenderer::GaugeRenderer():
Renderer(
application->GetApplicationLoopFrameRate(),
MaxRendererComplexity, // in renderer.cc (3.0f)
DefaultRendererPriority, // in renderer.hh (1)
GaugeInterestType, // in interest.hh
DefaultInterestDepth, // in interest.hh (1)
GaugeRendererClassID // in vdata.hh
),
newList(NULL),
activeList(NULL),
inactiveList(NULL),
lampManager(NULL) // instantiated at topmost level only
{
Test_Tell("GaugeRenderer::GaugeRenderer()\n");
Check_Pointer(this);
int
i;
suspended = False;
previousModeMask = (ModeMask) 0;
//---------------------------------------------------------------------
// Ensure that graphicsPort pointers are NULL
//---------------------------------------------------------------------
for (i=0; i<maximumGraphicsPorts; ++i)
{
graphicsPort[i] = NULL;
}
//---------------------------------------------------------------------
// Register the gauge map item collection objects
//---------------------------------------------------------------------
Register_Object(&movingEntities);
Register_Object(&staticEntities);
//----------------------------------------------------
// Add this object to the chain
//----------------------------------------------------
nextGaugeRenderer = headGaugeRenderer;
headGaugeRenderer = this;
//----------------------------------------------------
// Initialize the rate index
//----------------------------------------------------
rateBitMask = 0;
rateProfileIndex = 0;
//----------------------------------------------------
// Clear the warehouse pointer
//----------------------------------------------------
warehousePointer = NULL;
//----------------------------------------------------
// Create the interpreter
//----------------------------------------------------
interpreter = new GaugeInterpreter();
Register_Object(interpreter);
//----------------------------------------------------
// Clear the gauge alarm manager pointer
//----------------------------------------------------
gaugeAlarmManager = NULL;
//----------------------------------------------------
// Set up background processing
//----------------------------------------------------
taskMode = foreground;
activeIterator = new SChainIteratorOf<GaugeBase*>(activeList);
Register_Object(activeIterator);
//----------------------------------------------------
// Clear load-balancing data
//----------------------------------------------------
for(i=0; i<slotCount; ++i)
{
load[i] = (Scalar) 0;
}
//----------------------------------------------------
// Clear profiling data
//----------------------------------------------------
# if defined (PROFILE_GAUGES)
for (i=0; i<slotCount; ++i)
{
for (int j=0; j<tierCount; ++j)
{
statistics[i][j].Clear();
}
}
# endif
Check_Fpu();
}
//===========================================================================
// ~GaugeRenderer
//===========================================================================
GaugeRenderer::~GaugeRenderer()
{
Check(this);
Test_Tell("GaugeRenderer::~GaugeRenderer()\n");
//
//--------------------------------------------------------------------
// Delete local data structures
//--------------------------------------------------------------------
//
ShutdownImplementation();
//---------------------------------------------------------------------
// Delete the interpreter
//---------------------------------------------------------------------
Check(interpreter);
Unregister_Object(interpreter);
delete interpreter;
//---------------------------------------------------------------------
// Delete the gauge alarm manager
//---------------------------------------------------------------------
if (gaugeAlarmManager != NULL)
{
Check(gaugeAlarmManager);
Unregister_Object(gaugeAlarmManager);
delete gaugeAlarmManager;
}
//---------------------------------------------------------------------
// Delete the lamp manager
//---------------------------------------------------------------------
if (lampManager != NULL)
{
Unregister_Object(lampManager);
delete lampManager;
}
//---------------------------------------------------------------------
// Delete the active list background iterator
//---------------------------------------------------------------------
Unregister_Object(activeIterator);
delete activeIterator;
activeIterator = NULL;
//---------------------------------------------------------------------
// Unregister the gauge map item collection objects
//---------------------------------------------------------------------
Unregister_Object(&movingEntities);
Unregister_Object(&staticEntities);
//--------------------------------------------------------------------
// Unlink this object from the chain
//--------------------------------------------------------------------
GaugeRenderer
*gauge_renderer,
*previous_gauge_renderer(NULL);
//
// Search for 'this' in the chain
//
for(
gauge_renderer = headGaugeRenderer;
gauge_renderer != NULL;
gauge_renderer = gauge_renderer->nextGaugeRenderer
)
{
if (gauge_renderer == this)
{
//
// Found! head of list?
//
if (previous_gauge_renderer == NULL)
{
headGaugeRenderer = nextGaugeRenderer;
}
//
// Not head, remove from chain
//
else
{
previous_gauge_renderer->nextGaugeRenderer =
nextGaugeRenderer;
}
break;
}
//
// Keep track of 'previous' object
//
previous_gauge_renderer = gauge_renderer;
}
Check_Fpu();
}
//===========================================================================
// EmergencyShutdown
//===========================================================================
void
GaugeRenderer::EmergencyShutdown()
{
Test_Tell("GaugeRenderer::EmergencyShutdown()\n");
GaugeRenderer
*gauge_renderer;
for(
gauge_renderer = headGaugeRenderer;
gauge_renderer != NULL;
gauge_renderer = gauge_renderer->nextGaugeRenderer
)
{
gauge_renderer->LocalEmergencyShutdown();
}
}
//===========================================================================
// LocalEmergencyShutdown
//===========================================================================
void
GaugeRenderer::LocalEmergencyShutdown()
{
}
//
//===========================================================================
// TestInstance
//===========================================================================
//
Logical
GaugeRenderer::TestInstance() const
{
//--------------------------------------------------------------------
// Check the base renderer
//--------------------------------------------------------------------
return Renderer::TestInstance();
}
//
//===========================================================================
// LinkToEntity
//===========================================================================
//
void
GaugeRenderer::LinkToEntity(Entity *entity)
{
Check(this);
Check(entity);
Test_Tell("GaugeRenderer::LinkToEntity(" << entity << ")\n");
//
//--------------------------------------------------------------------
// Inform all gauges
//--------------------------------------------------------------------
//
GaugeBase
*base_pointer;
if (! suspended)
{
{
SChainIteratorOf<GaugeBase*>
i(newList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->LinkToEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(activeList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->LinkToEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(inactiveList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->LinkToEntity(entity);
}
}
}
//
//--------------------------------------------------------------------
// Call inherited method
//--------------------------------------------------------------------
//
Renderer::LinkToEntity(entity);
Check_Fpu();
}
//
//===========================================================================
// NotifyOfNewInterestingEntity
//===========================================================================
//
void
GaugeRenderer::NotifyOfNewInterestingEntity(Entity *entity)
{
Test_Tell("GaugeRenderer::NotifyOfNewInterestingEntity\n");
Check(this);
Check(entity);
//------------------------------------------------------
// This method used to update both the movingEntities
// and staticEntities records. That functionality has
// been moved up to the game-specific level (e.g.,
// RPL4GaugeRenderer) to allow the game to determine
// what to show. Note that all descendents MUST chain
// back to this base method...
//------------------------------------------------------
//
//--------------------------------------------------------------------
// Inform all gauges
//--------------------------------------------------------------------
//
GaugeBase
*base_pointer;
if (! suspended)
{
{
SChainIteratorOf<GaugeBase*>
i(newList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfNewInterestingEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(activeList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfNewInterestingEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(inactiveList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfNewInterestingEntity(entity);
}
}
}
Check_Fpu();
}
//
//===========================================================================
// NotifyOfBecomingUninterestingEntity
//===========================================================================
//
void
GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *entity)
{
Test_Tell("GaugeRenderer::NotifyOfBecomingUninterestingEntity\n");
Check(this);
Check(entity);
//------------------------------------------------------
// This method used to update both the movingEntities
// and staticEntities records. That functionality has
// been moved up to the game-specific level (e.g.,
// RPL4GaugeRenderer) to allow the game to determine
// what to show. Note that all descendents MUST chain
// back to this base method...
//------------------------------------------------------
//
//--------------------------------------------------------------------
// Inform all gauges
//--------------------------------------------------------------------
//
GaugeBase
*base_pointer;
if (! suspended)
{
{
SChainIteratorOf<GaugeBase*>
i(newList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfBecomingUninterestingEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(activeList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfBecomingUninterestingEntity(entity);
}
}
{
SChainIteratorOf<GaugeBase*>
i(inactiveList);
while ((base_pointer=i.ReadAndNext()) != NULL)
{
Check(base_pointer);
base_pointer->NotifyOfBecomingUninterestingEntity(entity);
}
}
}
Check_Fpu();
}
//
//===========================================================================
// Entity alarms
//===========================================================================
//
void
GaugeRenderer::StartEntityAlarmImplementation(
Entity *entity,
Subsystem *subsystem,
Enumeration condition,
ResourceDescription::ResourceID resource_ID
)
{
Check(this);
Check(gaugeAlarmManager);
gaugeAlarmManager->Activate(
entity,
subsystem,
condition,
resource_ID
);
Check_Fpu();
}
void
GaugeRenderer::StopEntityAlarmImplementation(
Entity *entity,
Subsystem *subsystem,
Enumeration condition
)
{
Check(this);
Check(gaugeAlarmManager);
gaugeAlarmManager->Deactivate(
entity,
subsystem,
condition
);
Check_Fpu();
}
//
//===========================================================================
// LoadMissionImplementation
//===========================================================================
//
void
GaugeRenderer::LoadMissionImplementation(Mission */*mission*/)
{
Tell("GaugeRenderer::LoadMissionImplementation()\n");
Check(this);
//DEBUG_STREAM << "Mover list has " <<
// movingGaugeImages.NumberOfItems() << "items.\n";
//staticGaugeImages.PrintStatistics();
Check_Fpu();
}
//
//===========================================================================
// ShutdownImplementation
//===========================================================================
//
void
GaugeRenderer::ShutdownImplementation()
{
Tell("GaugeRenderer::ShutdownImplementation()\n");
Check(this);
//--------------------------------------------------------------------
// Turn off all gauge alarms
//--------------------------------------------------------------------
if (gaugeAlarmManager != NULL)
{
Check(gaugeAlarmManager);
gaugeAlarmManager->RemoveAllAlarms();
}
//--------------------------------------------------------------------
// Delete all remaining gauges BEFORE clearing out the warehouse!
// ...otherwise the gauges will attempt to reference items which
// no longer exist in the warehouse...
//--------------------------------------------------------------------
Remove(0);
//--------------------------------------------------------------------
// Remove all lamps
//--------------------------------------------------------------------
if (lampManager != NULL)
{
Check(lampManager);
lampManager->RemoveAllLamps();
}
//--------------------------------------------------------------------
// Clear out the warehouse
//--------------------------------------------------------------------
if (warehousePointer != NULL)
{
Check(warehousePointer);
warehousePointer->Purge();
}
//--------------------------------------------------------------------
// Clear auxiliary data structures
//--------------------------------------------------------------------
movingEntities.Clear();
staticEntities.Clear();
//---------------------------------------------------------------------
// Destroy all graphicsPort objects
//---------------------------------------------------------------------
int
i;
for (i=0; i<maximumGraphicsPorts; ++i)
{
if (graphicsPort[i] != NULL)
{
Unregister_Object(graphicsPort[i]);
delete graphicsPort[i];
graphicsPort[i] = NULL;
}
}
Check_Fpu();
}
//
//===========================================================================
// SuspendImplementation
//===========================================================================
//
void
GaugeRenderer::SuspendImplementation()
{
Tell("GaugeRenderer::SuspendImplementation()\n");
Check(this);
suspended = True;
Check_Fpu();
}
//
//===========================================================================
// ResumeImplementation
//===========================================================================
//
void
GaugeRenderer::ResumeImplementation()
{
Tell("GaugeRenderer::ResumeImplementation()\n");
Check(this);
suspended = False;
Check_Fpu();
}
//
//===========================================================================
// FindGraphicsPort
//===========================================================================
//
int
GaugeRenderer::FindGraphicsPort(const char * port_name)
{
Test_Tell("GaugeRenderer::FindGraphicsPort(" << port_name << ")\n");
if (port_name != NULL)
{
for(int i=0; i<maximumGraphicsPorts; ++i)
{
if (graphicsPort[i] != NULL)
{
Test_Tell(graphicsPort[i]->name << " ");
if (stricmp(graphicsPort[i]->name, port_name) == 0)
{
Test_Tell("<-Found\n");
Check_Fpu();
return i;
}
}
}
}
Check_Fpu();
return -1;
}
//
//===========================================================================
// GetGraphicsPort
//===========================================================================
//
GraphicsPort
*GaugeRenderer::GetGraphicsPort(const char * port_name)
{
int i(FindGraphicsPort(port_name));
Check_Fpu();
if (i >= 0)
{
return graphicsPort[i];
}
return NULL;
}
GraphicsPort
*GaugeRenderer::GetGraphicsPort(int port_number)
{
Check_Fpu();
if ((port_number >= 0) && (port_number < maximumGraphicsPorts))
{
return graphicsPort[port_number];
}
else
{
return NULL;
}
}
//
//===========================================================================
// Add
//===========================================================================
//
void
GaugeRenderer::Add(GaugeBase *new_gauge)
{
Tell("GaugeRenderer::Add(" << std::hex << new_gauge << std::dec << ")\n");
Check(this);
//
// Don't call Check(new_gauge) here!
// The Gauge creator calls AddGauge before the gauge is fully built!
//
Check_Pointer(new_gauge);
//-------------------------------------------------------------------------
// Add to 'new' list
//-------------------------------------------------------------------------
newList.Add(new_gauge);
Check_Fpu();
}
//
//===========================================================================
// Remove
//===========================================================================
//
void
GaugeRenderer::Remove(unsigned int owner_ID)
{
Tell("GaugeRenderer::Remove(" << owner_ID << ")\n");
Check(this);
GaugeBase
*the_base;
//--------------------------------------------------
// Search active list first
//--------------------------------------------------
{
SChainIteratorOf<GaugeBase*>
i(activeList);
//--------------------------------------------------
// Process all matching gauges
//--------------------------------------------------
while ((the_base=i.GetCurrent()) != NULL)
{
Check(the_base);
if ((owner_ID == 0) || (the_base->ownerID == owner_ID))
{
//-----------------------------------------------
// 'Flush' the gauge before deleting it
//-----------------------------------------------
the_base->Update(Gauge::gaugeRate_A);
//-----------------------------------------------
// Delete it
//-----------------------------------------------
i.Remove();
Tell(the_base->identificationString << "\n" << flush);
Unregister_Object(the_base);
delete the_base;
}
else
{
i.Next();
}
}
}
//--------------------------------------------------
// Search inactive list second
//--------------------------------------------------
{
SChainIteratorOf<GaugeBase*>
i(inactiveList);
//--------------------------------------------------
// Process all matching gauges
//--------------------------------------------------
while ((the_base=i.GetCurrent()) != NULL)
{
Check(the_base);
if ((owner_ID == 0) || (the_base->ownerID == owner_ID))
{
//-----------------------------------------------
// Delete it
//-----------------------------------------------
i.Remove();
Tell(the_base->identificationString << "\n" << flush);
Unregister_Object(the_base);
delete the_base;
}
else
{
i.Next();
}
}
}
Check_Fpu();
}
//
//===========================================================================
// Remove
//===========================================================================
//
void
GaugeRenderer::Inactivate(GaugeBase *the_base)
{
Tell("GaugeRenderer::Inactivate(" << std::hex << the_base << std::dec << ")\n");
Check(this);
GaugeBase
*the_other_base;
//--------------------------------------------------
// Search active list for the base
//--------------------------------------------------
SChainIteratorOf<GaugeBase*>
i(activeList);
while ((the_other_base=i.GetCurrent()) != NULL)
{
Check(the_other_base);
if (the_base == the_other_base)
{
//-----------------------------------------------
// Remove from this list, place in inactive list
//-----------------------------------------------
i.Remove();
inactiveList.Add(the_base);
the_base->BecameInactive();
break;
}
else
{
i.Next();
}
}
Check_Fpu();
}
GaugeRate
GaugeRenderer::FindBestFirstTierRate()
{
return Gauge::gaugeRate_B; // HACK -stubbed in
}
GaugeRate
GaugeRenderer::FindBestSecondTierRate()
{
return Gauge::gaugeRate_D; // HACK -stubbed in
}
GaugeRate
GaugeRenderer::FindBestThirdTierRate()
{
return Gauge::gaugeRate_H; // HACK -stubbed in
}
GaugeRate
GaugeRenderer::FindBestFourthTierRate()
{
return Gauge::gaugeRate_P; // HACK -stubbed in
}
//
//===========================================================================
// ExecuteImplementation
//===========================================================================
//
void
GaugeRenderer::ExecuteImplementation(
RendererComplexity /*complexity*/,
RendererOrigin::InterestingEntityIterator */*iterator*/
)
{
SET_GAUGE_RENDERER();
Check(this);
if (! suspended)
{
if (taskMode == foreground)
{
ExecuteForeground();
}
}
Check_Fpu();
CLEAR_GAUGE_RENDERER();
}
//
//===========================================================================
// RebuildEntityGrid -- repopulate the moving/static entity grids from the world
// entity list (the port dropped ExecuteImplementation's InterestingEntity feed,
// so the radar/map gauge's within-bounds queries found no contacts).
//===========================================================================
//
void
GaugeRenderer::RebuildEntityGrid()
{
Check(this);
movingEntities.Clear();
staticEntities.Clear();
if (application == NULL)
{
return;
}
HostManager *host_manager = application->GetHostManager();
if (host_manager == NULL)
{
return;
}
// Radar contacts are the DYNAMIC vehicles (mechs), not the props/terrain/
// projectiles that AllEntityIterator would flood the grid with -- iterate the
// dynamic masters (the local + AI/dummy vehicles) plus the dynamic replicants
// (peer vehicles in multiplayer). Static beacons/props (a separate
// classification) are left for a follow-up.
{
HostManager::DynamicMasterEntityIterator master_iterator(host_manager);
master_iterator.First();
Entity *entity;
while ((entity = master_iterator.ReadAndNext()) != NULL)
{
movingEntities.Add(entity);
}
}
{
HostManager::DynamicReplicantEntityIterator replicant_iterator(host_manager);
replicant_iterator.First();
Entity *entity;
while ((entity = replicant_iterator.ReadAndNext()) != NULL)
{
movingEntities.Add(entity);
}
}
Check_Fpu();
}
void
GaugeRenderer::ExecuteForeground()
{
Check(this);
Check(activeIterator);
//-------------------------------------------------------------------
// Get the current mode mask
//-------------------------------------------------------------------
Check(application);
Check(application->GetModeManager());
ModeMask
current_mode_mask = application->GetModeManager()->GetModeMask();
ModeMask
previous_mode_mask = application->GetModeManager()->GetPreviousModeMask();
ModeMask
change_mode_mask = current_mode_mask ^ previous_mode_mask; // xor tells me what has changed
//-------------------------------------------------------------------
// Update lamp manager
//-------------------------------------------------------------------
if (lampManager != NULL)
{
Check(lampManager);
lampManager->Update(current_mode_mask);
}
//-------------------------------------------------------------------
// Move new gauges to active/inactive lists
//-------------------------------------------------------------------
{
SChainIteratorOf<GaugeBase*>
i(newList);
GaugeBase
*base_pointer;
while ((base_pointer=i.GetCurrent()) != NULL)
{
//-------------------------------------
// Always remove from 'new' list
//-------------------------------------
i.Remove();
//-------------------------------------
// Place in appropriate list
//-------------------------------------
Check(base_pointer);
if (base_pointer->modeMask & current_mode_mask)
{
// If not already flagged, or gauge's mode mask is always active,
// or the mode change affects us, place into active list
if (!(base_pointer->alreadyActivatedFlag)
// || (base_pointer->modeMask == ModeManager::ModeAlwaysActive)
|| (base_pointer->modeMask & change_mode_mask))
{
base_pointer->alreadyActivatedFlag = True;
//-------------------------------------
// Announce new status
//-------------------------------------
base_pointer->BecameActive();
//-------------------------------------
// Place in active list only if legal
//-------------------------------------
if (base_pointer->stayInactive)
{
inactiveList.Add(base_pointer);
}
else
{
activeList.Add(base_pointer);
}
}
}
else
{
inactiveList.Add(base_pointer);
}
}
}
//---------------------------------------------------------------
// If the modeMask has changed, update the active/inactive lists.
//---------------------------------------------------------------
if (previousModeMask != current_mode_mask)
{
previousModeMask = current_mode_mask;
ActivateGaugeBases(current_mode_mask,change_mode_mask);
DeactivateGaugeBases(current_mode_mask);
}
//---------------------------------------------------------------
// Restart background processing
//---------------------------------------------------------------
taskMode = background;
activeIterator->First();
//--------------------------------
// Reset rate bit mask if needed
//--------------------------------
if (rateBitMask == 0)
{
rateBitMask = 0x8000;
# if defined (PROFILE_GAUGES)
rateProfileIndex = 0;
# endif
}
Check_Fpu();
}
//
//===========================================================================
// ExecuteBackground
//===========================================================================
//
Logical
GaugeRenderer::ExecuteBackground()
{
SET_GAUGE_RENDERER();
Check(this);
Logical
result;
Time start, end;
int oldTaskMode = taskMode;
switch(taskMode)
{
case foreground:
result = ExecuteBackgroundDisplayUpdate(); // might as well update
break;
case background:
{
result = ProcessOneActiveGauge();
break;
}
case copy:
result = ExecuteBackgroundDisplayUpdate();
break;
}
if (end.ticks - start.ticks > 100)
{
end = start;
}
Check_Fpu();
CLEAR_GAUGE_RENDERER();
return result;
}
Logical
GaugeRenderer::ExecuteBackgroundDisplayUpdate()
{
Check(this);
return False;
}
//
//===========================================================================
// ActivateGaugeBases
//===========================================================================
//
void
GaugeRenderer::ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask)
{
Check(this);
//-----------------------------------------------------------
// Test the objects in the 'inactive' list. If any of them
// have bits in their modeMask corresponding to the
// new mode mask, move them to the 'active' list.
//-----------------------------------------------------------
SChainIteratorOf<GaugeBase*>
i(inactiveList);
GaugeBase
*base_pointer;
while ((base_pointer=i.GetCurrent()) != NULL)
{
Check(base_pointer);
//-----------------------------------
// Became active?
//-----------------------------------
if (base_pointer->modeMask & current_mode_mask)
{
if (!(base_pointer->alreadyActivatedFlag)
// || (base_pointer->modeMask == ModeManager::ModeAlwaysActive)
|| (base_pointer->modeMask & change_mode_mask))
{
#if 0
DEBUG_STREAM << "Activating an inactive (not visible) gauge on inactive list" << endl << std::flush;
#endif
//-----------------------------------
// Inform object of new status
//-----------------------------------
base_pointer->BecameActive();
base_pointer->alreadyActivatedFlag = True;
//-----------------------------------
// Move to 'active' list if allowed
//-----------------------------------
if (base_pointer->stayInactive)
{
i.Next();
}
else
{
i.Remove();
activeList.Add(base_pointer);
}
}
else
{
i.Next();
}
}
else
{
//-----------------------------------
// No, try the next one
//-----------------------------------
i.Next();
}
}
Check_Fpu();
}
//
//===========================================================================
// DeactivateGaugeBases
//===========================================================================
//
void
GaugeRenderer::DeactivateGaugeBases(ModeMask current_mode_mask)
{
Check(this);
//---------------------------------------------------------------
// Test the objects in the 'active' list. If any of them do NOT
// have bits in their modeMask corresponding to the new mode
// mask, move them to the 'inactive' list.
//---------------------------------------------------------------
SChainIteratorOf<GaugeBase*>
i(activeList);
GaugeBase
*base_pointer;
while ((base_pointer=i.GetCurrent()) != NULL)
{
Check(base_pointer);
//-----------------------------------
// Became inactive?
//-----------------------------------
if (!(base_pointer->modeMask & current_mode_mask))
{
base_pointer->alreadyActivatedFlag = False;
//-----------------------------------
// Yes, move to 'inactive' list
//-----------------------------------
i.Remove();
inactiveList.Add(base_pointer);
base_pointer->BecameInactive();
}
else
{
//-----------------------------------
// No, try the next one
//-----------------------------------
i.Next();
}
}
Check_Fpu();
}
//
//===========================================================================
// ProcessOneActiveGauge
//===========================================================================
//
Logical
GaugeRenderer::ProcessOneActiveGauge()
{
Check(this);
Check(activeIterator);
Logical
result;
GaugeBase
*base_pointer = activeIterator->ReadAndNext();
if (base_pointer == NULL)
{
//--------------------------------------------------
// We're done!
// Bump the bit mask and index for the next pass
//--------------------------------------------------
rateBitMask >>= 1;
# if defined (PROFILE_GAUGES)
++rateProfileIndex;
# endif
//--------------------------------------------------
// Inform system that we are finished
//--------------------------------------------------
taskMode = copy;
result = True; // Don't stop just yet! Go into third phase!
}
else
{
//--------------------------------------------------
// Process one gauge
//--------------------------------------------------
Check(base_pointer);
# if defined (PROFILE_GAUGES)
Scalar
delta = GetCurrentFramePercentage();
Logical
actually_ran =
# endif
base_pointer->Update(rateBitMask);
# if defined (PROFILE_GAUGES)
delta = GetCurrentFramePercentage() - delta;
if (delta < (Scalar) 0)
{
// Hack - what does it REALLY mean when it's negative?!?
delta = - delta;
}
if (actually_ran)
{
base_pointer->UpdateProfile(delta);
}
statistics[rateProfileIndex][base_pointer->DiscernTier()]
.Update(delta);
# endif
//--------------------------------------------------
// Tell renderer manager that we have more to do
//--------------------------------------------------
result = True;
}
return result;
}
//
//===========================================================================
// GetCurrentFramePercentage
//===========================================================================
//
Scalar
GaugeRenderer::GetCurrentFramePercentage()
{
Check(this);
return (Scalar) 0;
}
enum
{
average_bar,
maximum_bar
};
#if defined (PROFILE_GAUGES)
static Scalar
draw_bar(
GaugeRenderer *renderer,
int bar_width,
int slot_index,
int bar_type
)
{
Check(renderer);
//------------------------------------
// Show individual tier contributors
//------------------------------------
Scalar
value,
total_value = (Scalar) 0;
Scalar
position = (Scalar) 0;
int
tier_index,
char_position = 0,
next_char_position;
for(tier_index=0; tier_index<GaugeRenderer::tierCount; ++tier_index)
{
//------------------------------------
// Choose tier marker to print
//------------------------------------
static char
*tier_number[GaugeRenderer::slotCount] =
{
"ABDHP",
"ABDHQ",
"ABDIR",
"ABDIS",
"ABEJT",
"ABEJU",
"ABEKV",
"ABEKW",
"ACFLX",
"ACFLY",
"ACFMZ",
"ACFM0",
"ACGN1",
"ACGN2",
"ACGo3",
"ACGo4",
};
char
tier_marker = tier_number[slot_index][tier_index];
//------------------------------------
// Get, clear tier statistics
//------------------------------------
switch(bar_type)
{
default:
value=
renderer->statistics[slot_index][tier_index].CalculateAverage();
break;
case maximum_bar:
value=
renderer->statistics[slot_index][tier_index].maximum;
break;
}
//------------------------------------
// Add to total
// Calculate next bar position
//------------------------------------
total_value += value;
position += bar_width * value;
//------------------------------------
// Limit it in case of overflow
//------------------------------------
if (position > (Scalar) bar_width)
{
position = (Scalar) bar_width;
}
//------------------------------------
// Draw with marker to next position
//------------------------------------
next_char_position = (int) position;
for( ; char_position < next_char_position; ++char_position)
{
DEBUG_STREAM << tier_marker << std::flush;
}
}
//------------------------------------
// Fill unused space in bar
//------------------------------------
for( ; char_position < bar_width; ++char_position)
{
DEBUG_STREAM << "." << std::flush;
}
Check_Fpu();
return total_value;
}
#endif
void
GaugeRenderer::ProfileReport()
{
Check(this);
# if defined (PROFILE_GAUGES)
//--------------------------------------------------------------
// Show all gauges
//--------------------------------------------------------------
{
SChainIteratorOf<GaugeBase*>
i(activeList);
GaugeBase
*the_base;
DEBUG_STREAM <<"Active name count avg worst\n" << std::flush;
DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush;
while ((the_base=i.ReadAndNext()) != NULL)
{
Check(the_base);
the_base->ReportProfile();
}
}
{
SChainIteratorOf<GaugeBase*>
i(inactiveList);
GaugeBase
*the_base;
DEBUG_STREAM <<"Inactive name count avg worst\n" << std::flush;
DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << std::flush;
while ((the_base=i.ReadAndNext()) != NULL)
{
Check(the_base);
the_base->ReportProfile();
}
}
//--------------------------------------------------------------------
// Dump profiling data
//--------------------------------------------------------------------
int
slot_index,
tier_index,
bar_width = 40; // total width of bar graph
char
buffer[80];
//------------------------------------
// Print header bar
//------------------------------------
DEBUG_STREAM << "\nSlot|Count|Tier values " << std::flush;
DEBUG_STREAM << "|Total %\n" << std::flush;
DEBUG_STREAM << "----+-----+" << std::flush;
{
for(int i=0; i<bar_width; ++i)
{
DEBUG_STREAM << "-" << std::flush;
}
DEBUG_STREAM << "+-------\n" << std::flush;
}
for(slot_index=0; slot_index<slotCount; ++slot_index)
{
//------------------------------------
// Print slot number header
//------------------------------------
sprintf(buffer, "%2d |", slot_index);
DEBUG_STREAM << buffer << std::flush;
//------------------------------------
// Get total number of samples
//------------------------------------
int
sample_count = 0;
for(tier_index=0; tier_index<tierCount; ++tier_index)
{
sample_count += statistics[slot_index][tier_index].sampleCount;
}
//------------------------------------
// If no data, say so
//------------------------------------
if (sample_count <= 0)
{
DEBUG_STREAM << "No samples available\n" << std::flush;
}
else
{
//------------------------------------
// Show average values
//------------------------------------
sprintf(buffer, "%5d|", sample_count);
DEBUG_STREAM << buffer << std::flush;
Scalar
total_average = draw_bar(
this, bar_width, slot_index, average_bar
);
sprintf(buffer, "|%5.2f%%\n", total_average * (Scalar) 100);
DEBUG_STREAM << buffer << std::flush;
//------------------------------------
// Show maximum values
//------------------------------------
DEBUG_STREAM << " |Worst|" << std::flush;
Scalar
total_worst = draw_bar(
this, bar_width, slot_index, maximum_bar
);
sprintf(buffer, "|%5.2f%%\n", total_worst * (Scalar) 100);
DEBUG_STREAM << buffer << std::flush;
//------------------------------------
// Clear stats
//------------------------------------
for(tier_index=0; tier_index<tierCount; ++tier_index)
{
statistics[slot_index][tier_index].Clear();
}
}
}
# endif
Check_Fpu();
}
//
//===========================================================================
// Configuration
//===========================================================================
//
void
GaugeRenderer::BuildConfigurationFile(
const char *file_name,
MethodDescription **method_description
)
{
Test_Tell(
"GaugeRenderer::BuildConfigurationFile('" << file_name <<
"', " << method_description <<
")\n"
);
Check(this);
Check_Pointer(file_name);
Check_Pointer(method_description);
//-----------------------------------------------
// Initialize the interpreter
//-----------------------------------------------
Check(interpreter);
interpreter->Initialize(file_name, method_description, warehousePointer);
//-----------------------------------------------
// Execute app initialization call, if it exists
//-----------------------------------------------
Configure("Initialization", NULL);
Check_Fpu();
}
void
GaugeRenderer::Configure(
const char *label,
Entity *entity
)
{
Test_Tell(
"GaugeRenderer::Configure('" << label <<
"', " << entity <<
")\n"
);
Check(this);
Check_Pointer(label);
Vector2DOf<int>
position;
position.x = 0;
position.y = 0;
Check(interpreter);
interpreter->Interpret(label, this, 0, position, entity);
Check_Fpu();
}