The "sectorDisplay" cockpit primitive (Secondary overlay, the radar SECTOR X/Z coordinate read-out) was PROSE-ONLY in btl4gau3 (placeholder Make, no ctor/ methodDescription/registration) -> the config line was parse-SKIPPED and never built. Reconstructed byte-verified from the disassembly (ctor @4c9e10, Execute @4ca07c, methodDescription PE-parse): SectorDisplay : GraphicGauge, sizeof 0xC4. Its Execute reads the linked mech's world position and shows two 100-unit sector numerics: numericA = Round(-localOrigin.z * 0.01) + 500 numericB = Round( localOrigin.x * 0.01) + 500 (rounding = round-to-nearest == FUN_004dcd94, corrected from the reviewer's wrong "truncate" claim; 0.01 const PE-verified; -Z/+X axis + fchs confirmed from asm). Overridden slots: LinkToEntity(9) caches the subject, BecameActive(3, non-inactivating), Execute(16) -> satisfies the container-Execute rule. Layout overflow-locked (static_assert sizeof<=0xC4). Make/ctor/dtor mirror the registered PilotList sibling; the config image name is copied (nameCopy) since Execute reads it per-frame. Registered in BTL4MethodDescription[]. VERIFIED LIVE (BT_SECTOR_LOG): Make port=1 pos=(125,579) image=helv15.pcc gridCached=1; Execute -Z=960.4 X=361.6 -> sectorA=510 sectorB=504 (Round(9.6)+500=510, Round(3.6)+500=504 -- authentic 100-unit sectors from live mech position). Gauge composite renders full, no crash. The skip list is now exactly the two remaining widgets (prepEngr x12, messageBoard). Also: a permanent BT_GAUGE_SKIP_LOG diagnostic (GAUGREND.cpp, gated) that logs each unregistered gauge primitive the dev-parse skips -- the tool that pinned this down (earlier "not built" runs were killed before the lazy gauge-renderer init). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4296 lines
98 KiB
C++
4296 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)
|
|
{
|
|
if (getenv("BT_GAUGE_SKIP_LOG"))
|
|
DEBUG_STREAM << "[gskip] unresolved primitive '"
|
|
<< local_name << "' -> skipped\n" << std::flush;
|
|
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();
|
|
}
|