Playtest: "after I destroyed the mech the red blip was still on my radar." The authentic engine adds/removes radar contacts through the interest feed (GaugeRenderer::NotifyOfNewInterestingEntity / NotifyOfBecomingUninterestingEntity), and the game decides what's a contact -- a dying mech becoming uninteresting is removed, so the blip drops. The port DROPPED that feed and rebuilds the radar grid every frame from EVERY dynamic mover (RebuildEntityGrid), so it never removed the dead one and the red blip lingered on the frozen wreck (the wreck stays as an entity by design; only its model sinks/buries). Fix: in RebuildEntityGrid, skip a destroyed/disabled mover (GetSimulationState() == 2 || 9 -- the movementMode wreck latch, unified with simulationState) so it leaves the moving/red-contact grid. Live movers unaffected; the blip drops on death. Verified (BT_MAP_LOG): the killed enemy (ent cls=0xbb9) is drawn ONCE at the death-transition frame (the 1-frame lag before movementMode latches to 9) then never again for the rest of the session, while the owner keeps drawing every cycle. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4333 lines
100 KiB
C++
4333 lines
100 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).
|
|
// CLASSIFICATION (the phantom-red-pip fix, 2026-07-12): the dynamic
|
|
// iterators ALSO surface non-Mover world entities (the map's CulturalIcon
|
|
// props, class 0x5E, register dynamic on this port) -- unsorted, they drew
|
|
// through the radar's MOVING loop as RED contacts ("multiple pips with one
|
|
// player"). Sort by Mover derivation: vehicles into the moving grid (red
|
|
// pips), everything else into the static grid (the dim silhouette layer
|
|
// DrawStatic draws) -- the follow-up the old note deferred.
|
|
{
|
|
HostManager::DynamicMasterEntityIterator master_iterator(host_manager);
|
|
master_iterator.First();
|
|
Entity *entity;
|
|
while ((entity = master_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if (entity->IsDerivedFrom(*Mover::GetClassDerivations()))
|
|
{
|
|
// DEAD-MECH RADAR DROP (2026-07-20): a destroyed/disabled mover
|
|
// (movementMode 2||9 == the wreck latch, unified with
|
|
// simulationState) is no longer a live sensor contact. The
|
|
// authentic engine removes it via the interest feed
|
|
// (NotifyOfBecomingUninterestingEntity); the port's per-frame
|
|
// grid-rebuild dropped that feed, so the red blip lingered on the
|
|
// frozen wreck after the kill. Skip it -> blip goes away on death.
|
|
unsigned st = entity->GetSimulationState();
|
|
if (st != 2 && st != 9)
|
|
movingEntities.Add(entity);
|
|
}
|
|
else
|
|
staticEntities.Add(entity);
|
|
}
|
|
}
|
|
{
|
|
HostManager::DynamicReplicantEntityIterator replicant_iterator(host_manager);
|
|
replicant_iterator.First();
|
|
Entity *entity;
|
|
while ((entity = replicant_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
if (entity->IsDerivedFrom(*Mover::GetClassDerivations()))
|
|
{
|
|
unsigned st = entity->GetSimulationState(); // dead-mech radar drop (see the master loop above)
|
|
if (st != 2 && st != 9)
|
|
movingEntities.Add(entity);
|
|
}
|
|
else
|
|
staticEntities.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();
|
|
// DEV-COMPOSITE history: a 2026-07-12 scaffold ("the frozen-dial fix")
|
|
// forced the 15 MFD page-plane bits (BTL4 mode bits 0..14 = MFD1/2/3
|
|
// Quad+Eng1-4) active under BT_DEV_GAUGES, because the dev panel then drew
|
|
// every page plane at once and page-gated dials froze. REMOVED for Gitea
|
|
// #9 (2026-07-19): the dev composite now honors the mode-driven
|
|
// `reconfigure` (a BlankColor plane is skipped -- L4VB16.cpp
|
|
// BTDrawGaugeSurfaces), so exactly the ACTIVE page of each MFD is shown,
|
|
// like the pod -- and the working SetPresetMode page switching NEEDS the
|
|
// authentic gating (the force made every eng screen paint over the shared
|
|
// Eng plane, pinning it on the highest screen and ignoring page flips).
|
|
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();
|
|
}
|