Files
RP412/MUNGA/GAUGREND.cpp
T
CydandClaude Opus 5 b7b2c3b148 The GPU transforms the vertices
The cockpit displays were updating every two to three seconds while the
3D view held a perfectly smooth 55 fps. This is why, and it is one line.

Every device was created D3DCREATE_SOFTWARE_VERTEXPROCESSING - every
vertex on the track transformed and lit on the CPU, on the one core this
game uses for everything. That was not a choice when the engine was
written; there was no hardware to hand it to. The error message beneath
the call still says "Couldn't create HARDWARE_VERTEXPROCESSING device",
so the flag was changed at some point and the message left behind.

Measured on the biggest track, 1920x1080:

  software   foreground 17.2 ms   background 1.2 ms   2.4 gauge passes/s
  hardware   foreground  0.2 ms   background 17.9 ms  50.0 gauge passes/s

The frame loop runs the foreground and then spends whatever is LEFT on
the background gauge work. A foreground costing 17.2 ms of an 18 ms frame
leaves nothing, so the gauge loop got the single pass it is guaranteed
and no more. A pass needs about twenty steps - eighteen gauges and three
display copies - so the cockpit ran at two passes a second, and since the
renderer walks a sixteen-step rate wheel, a gauge on one step redrew once
per SIXTEEN of those. Three seconds. The map, the clock, the boost gauge
and the sim still running after the fade to black were all that one
number.

Hardware T&L is now the default and sw is the way back. Fixed-function
lighting and fog are not bit-identical between the old software path and
a driver, so the escape hatch stays - but the picture was checked against
both and the difference is not the one worth defending. A cockpit whose
instruments update twice a second is. It falls back to software by itself
if the adapter has no hardware T&L.

The instruments that found it stay in, because nothing about this was
visible from outside:

- FrameSplit, under RP412GAUGEDIAG, reports foreground against background
  against whole frame. APPMGR has computed those four timestamps every
  frame since forever and never reported one of them; it would have
  pointed here on the first day.
- FrameDiag reports frames per second on the same window, so the gauge
  sweep rate can be read against the frame rate rather than guessed at.
- ProfileReport, which already existed and was only reachable through F11
  on the RIO controls mapper - not the mapper a desktop player runs, so
  in practice unreachable - now runs on a timer under RP412GAUGEPROFILE.
  Its per-gauge line gains the rate mask and tier, which is what names a
  display as one-in-sixteen rather than merely slow.
- The winners' circle logs what its exterior and name-plate rebuilds
  cost, since nothing else runs while they do.

RP412VSYNC is here too, and it is honest about itself: presenting
IMMEDIATE was measured and made no difference to the frame budget,
because the frame was full of work rather than waiting. It stays as a
latency-against-tearing preference, not a fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 13:12:34 -05:00

4296 lines
97 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "gaugrend.h"
#include "lamp.h"
#include "mover.h"
#include "terrain.h"
#include "app.h"
// #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
//
// How long a single background pass may spend drawing gauges, in
// milliseconds. RP412GAUGESLICE tunes it; 0 restores the original
// behaviour of exactly one gauge per pass.
//
static long
GaugeSliceMs()
{
static long
slice = -1L;
if (slice < 0L)
{
const char
*setting = getenv("RP412GAUGESLICE");
slice = (setting != NULL) ? atol(setting) : 2L;
if (slice < 0L)
{
slice = 0L;
}
}
return slice;
}
//#######################################################################
// 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
)
{
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"
);
}
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"
);
}
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();
}
void
GaugeRenderer::ExecuteForeground()
{
Check(this);
Check(activeIterator);
//-------------------------------------------------------------------
// Get the current mode mask
//-------------------------------------------------------------------
Check(application);
Check(application->GetModeManager());
ModeMask
current_mode_mask = application->GetModeManager()->GetModeMask();
ModeMask
previous_mode_mask = application->GetModeManager()->GetPreviousModeMask();
ModeMask
change_mode_mask = current_mode_mask ^ previous_mode_mask; // xor tells me what has changed
//-------------------------------------------------------------------
// Update lamp manager
//-------------------------------------------------------------------
if (lampManager != NULL)
{
Check(lampManager);
lampManager->Update(current_mode_mask);
}
//-------------------------------------------------------------------
// Move new gauges to active/inactive lists
//-------------------------------------------------------------------
{
SChainIteratorOf<GaugeBase*>
i(newList);
GaugeBase
*base_pointer;
while ((base_pointer=i.GetCurrent()) != NULL)
{
//-------------------------------------
// Always remove from 'new' list
//-------------------------------------
i.Remove();
//-------------------------------------
// Place in appropriate list
//-------------------------------------
Check(base_pointer);
if (base_pointer->modeMask & current_mode_mask)
{
// If not already flagged, or gauge's mode mask is always active,
// or the mode change affects us, place into active list
if (!(base_pointer->alreadyActivatedFlag)
// || (base_pointer->modeMask == ModeManager::ModeAlwaysActive)
|| (base_pointer->modeMask & change_mode_mask))
{
base_pointer->alreadyActivatedFlag = True;
//-------------------------------------
// Announce new status
//-------------------------------------
base_pointer->BecameActive();
//-------------------------------------
// Place in active list only if legal
//-------------------------------------
if (base_pointer->stayInactive)
{
inactiveList.Add(base_pointer);
}
else
{
activeList.Add(base_pointer);
}
}
}
else
{
inactiveList.Add(base_pointer);
}
}
}
//---------------------------------------------------------------
// If the modeMask has changed, update the active/inactive lists.
//---------------------------------------------------------------
if (previousModeMask != current_mode_mask)
{
previousModeMask = current_mode_mask;
ActivateGaugeBases(current_mode_mask,change_mode_mask);
DeactivateGaugeBases(current_mode_mask);
}
//---------------------------------------------------------------
// Restart background processing
//---------------------------------------------------------------
taskMode = background;
activeIterator->First();
//--------------------------------
// Reset rate bit mask if needed
//--------------------------------
if (rateBitMask == 0)
{
rateBitMask = 0x8000;
# if defined (PROFILE_GAUGES)
rateProfileIndex = 0;
# endif
}
Check_Fpu();
}
//
//===========================================================================
// ExecuteBackground
//===========================================================================
//
Logical
GaugeRenderer::ExecuteBackground()
{
SET_GAUGE_RENDERER();
Check(this);
Logical
result;
//
// RP412GAUGEPROFILE=<seconds> - dump the gauge profile on that
// cadence. Off unless set.
//
// ProfileReport already exists and PROFILE_GAUGES is already on, so
// the numbers are being collected whether anyone looks or not. It was
// only reachable from F11 through the RIO controls mapper, which is
// not the mapper a desktop player is running - so on PAD;KEYBOARD it
// could not be reached at all. This gives it a way out.
//
// It reports every gauge with its rate, its tier, how many times it
// ran and what it cost, then clears - so each dump covers the
// interval since the last one rather than all of history.
//
{
static long
profileInterval = -1L;
if (profileInterval < 0L)
{
const char
*setting = getenv("RP412GAUGEPROFILE");
profileInterval = (setting != NULL) ? atol(setting) : 0L;
if (profileInterval < 0L)
{
profileInterval = 0L;
}
}
if (profileInterval > 0L)
{
static Logical
profileScheduled = False;
static Time
profileDue;
Time
profileNow = Now();
if (!profileScheduled)
{
profileScheduled = True;
profileDue = profileNow;
profileDue += profileInterval * 1000L;
}
else if (profileDue < profileNow)
{
profileDue = profileNow;
profileDue += profileInterval * 1000L;
ProfileReport();
}
}
}
Time start, end;
int oldTaskMode = taskMode;
switch(taskMode)
{
case foreground:
result = ExecuteBackgroundDisplayUpdate(); // might as well update
break;
case background:
{
//-----------------------------------------------------------
// Draw gauges until the slice is spent, rather than exactly
// one per pass.
//
// The background loop is only guaranteed a single pass per
// frame; it gets more only while time remains before the
// frame is due. On a busy map the 3D foreground eats the
// whole budget, so a cycle of ninety-odd gauges takes
// ninety-odd frames to come round and the displays sit
// frozen for seconds. Working to a slice makes the refresh
// rate depend on elapsed time instead of on how much spare
// frame there happened to be.
//-----------------------------------------------------------
Time slice_end = Now();
slice_end += GaugeSliceMs();
do
{
result = ProcessOneActiveGauge();
}
while (result && taskMode == background && Now() < slice_end);
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();
}