mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 13:55:38 +00:00
Removed unused (and non-functional) 'stack machine' scene graph traversal.
This commit is contained in:
parent
4c7fe2f266
commit
b57ba51e44
|
@ -443,9 +443,7 @@ const UINT32 *CRender3D::TranslateModelAddress(UINT32 modelAddr)
|
|||
|
||||
|
||||
/******************************************************************************
|
||||
Stack Management
|
||||
|
||||
Matrix and processing stack (for the experimental stack-based scene parser).
|
||||
Matrix Stack
|
||||
******************************************************************************/
|
||||
|
||||
// Macro to generate column-major (OpenGL) index from y,x subscripts
|
||||
|
@ -541,72 +539,6 @@ void CRender3D::InitMatrixStack(UINT32 matrixBaseAddr)
|
|||
MultMatrix(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Push():
|
||||
*
|
||||
* Pushes a pointer onto the processing stack and, optionally, pushes the
|
||||
* current matrix onto the matrix stack. Note that the high nibble is used by
|
||||
* Supermodel to encode commands (such as pushing the matrix stack, and other
|
||||
* operations within the stack machine). We must be careful to ensure that no
|
||||
* games ever write data to this high nibble.
|
||||
*/
|
||||
void CRender3D::Push(UINT32 ptr, bool pushMatrix)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if ((ptr&0xF0000000)) // high nibble already being used for something!
|
||||
printf("Push(): MSB already in use!\n");
|
||||
#endif
|
||||
|
||||
// MSB of address is used to encode whether or not matrix has been pushed
|
||||
if (pushMatrix)
|
||||
ptr |= 0x80000000;
|
||||
|
||||
if (stackTop < stackSize)
|
||||
{
|
||||
stack[stackTop++] = ptr;
|
||||
if (pushMatrix)
|
||||
{
|
||||
glPushMatrix();
|
||||
#ifdef DEBUG
|
||||
if (glGetError() == GL_STACK_OVERFLOW)
|
||||
printf("GL stack overflow\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stackOverflow = true; // signal that a stack overflow occurred
|
||||
#ifdef DEBUG
|
||||
printf("stack overflow\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Pop the stack
|
||||
UINT32 CRender3D::Pop(void)
|
||||
{
|
||||
UINT32 ptr;
|
||||
|
||||
if (stackTop > 0)
|
||||
{
|
||||
ptr = stack[--stackTop];
|
||||
if ((ptr&0x80000000))
|
||||
{
|
||||
glPopMatrix();
|
||||
ptr &= 0x7FFFFFFF;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Clear the stack
|
||||
void CRender3D::ClearStack(void)
|
||||
{
|
||||
stackTop = 0;
|
||||
stackOverflow = false;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Scene Database
|
||||
|
@ -839,193 +771,6 @@ void CRender3D::DescendNodePtr(UINT32 nodeAddr)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* StackMachine():
|
||||
*
|
||||
* The new scene traversal engine. Uses a "processing stack" to avoid
|
||||
* recursion when traversing the scene graph. The real hardware almost
|
||||
* certainly does something similar, although it probably does not use a stack
|
||||
* for everything (for instance, display lists).
|
||||
*
|
||||
* If the OpenGL stack is pushed/popped as frequently as the node pointers, it
|
||||
* will rapidly overflow. Therefore, it is only saved when necessary (while
|
||||
* processing the first link in a culling node).
|
||||
*
|
||||
* Some games have been observed to create circular references in their display
|
||||
* lists (a culling node at some point will call the same display list from
|
||||
* which it was called). To handle this unusual situation, the stack machine
|
||||
* function maintains a small "stack" of list pointers. To pop this stack,
|
||||
* specially encoded pointers are pushed on the processing stack. It is assumed
|
||||
* that no games use the upper nibble of the node pointers for anything.
|
||||
*
|
||||
* Problems
|
||||
* --------
|
||||
* For some reason, terminating early can corrupt the OpenGL stack, so I've
|
||||
* added code to pop everything. It's still slower than the recursive method.
|
||||
*/
|
||||
void CRender3D::StackMachine(UINT32 nodeAddr)
|
||||
{
|
||||
unsigned listStackDepth = 0;
|
||||
|
||||
// Push this address on to the stack to begin the process
|
||||
Push(nodeAddr,false);
|
||||
|
||||
// Process the stack (keep popping until all finished)
|
||||
while (stackTop > 0)
|
||||
{
|
||||
unsigned nodeType;
|
||||
|
||||
// Pop
|
||||
nodeAddr = Pop();
|
||||
|
||||
// Check for our special "list stack" indicator
|
||||
if ((nodeAddr&0x40000000))
|
||||
{
|
||||
listStackDepth--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine how to process this node
|
||||
nodeType = (nodeAddr>>24)&0xFF; // extract type
|
||||
nodeAddr &= 0x00FFFFFF; // extract the address itself
|
||||
if (nodeAddr == 0) // ignore null links
|
||||
continue;
|
||||
switch (nodeType)
|
||||
{
|
||||
/*
|
||||
* Unknown
|
||||
*/
|
||||
default:
|
||||
//printf("ATTENTION: Unknown pointer format: %08X\n\n", nodeAddr);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Model
|
||||
*/
|
||||
case 0x01:
|
||||
case 0x03: // perhaps bit 1 is a flag?
|
||||
if (DrawModel(nodeAddr&0x00FFFFFF))
|
||||
goto PopAll;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Display List
|
||||
*
|
||||
* Circular references in display lists are handled with a nasty hack
|
||||
* here which abuses the processing stack by encoding a bit into the
|
||||
* highest nibble of a pointer. Note that we may have to maintain an
|
||||
* actual list stack in case more than a few nested lists are used
|
||||
* without circular references (in that case, we would have to scan the
|
||||
* list stack each time for duplicates). For now, we use the simple
|
||||
* approach.
|
||||
*/
|
||||
case 0x04:
|
||||
const UINT32 *list;
|
||||
|
||||
list = TranslateCullingAddress(nodeAddr);
|
||||
if (NULL == list)
|
||||
break;
|
||||
|
||||
// Push our special "list stack" indicator onto the stack, if there is room
|
||||
if (listStackDepth > 4) // probably indicates a recursive list
|
||||
break;
|
||||
else
|
||||
{
|
||||
Push(0x40000000,NULL);
|
||||
listStackDepth++;
|
||||
}
|
||||
|
||||
// Push all list elements onto stack (they will be processed backwards)
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
nodeAddr = list[i]&0x00FFFFFF; // clear upper 8 bits to ensure this is processed as a culling node
|
||||
if (nodeAddr==0) // we went too far, the display list has ended
|
||||
break;
|
||||
//if (((list[i]>>24)&0xFC) != 0)
|
||||
// ErrorLog("Unrecognized pointer format in display list: %08X\n", list[i]);
|
||||
if (!(list[i]&0x01000000)) // Fighting Vipers (this bit seems to indicate "do not process"
|
||||
{
|
||||
if ((nodeAddr != 0) && (nodeAddr != 0x800800))
|
||||
Push(nodeAddr,false); // don't need to save matrix (each culling node saves/restores matrix)
|
||||
}
|
||||
|
||||
if ((list[i]&0x02000000)) // list terminator
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Culling Node
|
||||
*
|
||||
* The current matrix stack must be saved when processing a culling
|
||||
* node and restored after the first link is finished. Therefore,
|
||||
* the only point at which the matrix needs to be saved is when pushing
|
||||
* the second link onto the processing stack. In other words, the
|
||||
* second link is more of a "JUMP" than a nested "CALL."
|
||||
*/
|
||||
case 0x00:
|
||||
const UINT32 *node, *lodTable;
|
||||
UINT32 matrixOffset, node1Ptr, node2Ptr;
|
||||
float x, y, z;
|
||||
|
||||
// Get pointer
|
||||
node = TranslateCullingAddress(nodeAddr);
|
||||
if (NULL == node) // invalid address, ignore
|
||||
break;
|
||||
|
||||
// Extract known fields
|
||||
node1Ptr = node[0x07-offset];
|
||||
node2Ptr = node[0x08-offset];
|
||||
matrixOffset = node[0x03-offset]&0xFFF;
|
||||
x = *(float *) &node[0x04-offset];
|
||||
y = *(float *) &node[0x05-offset];
|
||||
z = *(float *) &node[0x06-offset];
|
||||
|
||||
// Push second link on stack (this also saves current matrix and will ensure it is restored)
|
||||
Push(node2Ptr,true);
|
||||
|
||||
// Apply matrix and translation, then process first link
|
||||
if ((node[0x00]&0x10)) // apply translation vector
|
||||
glTranslatef(x,y,z);
|
||||
else if (matrixOffset) // multiply matrix, if specified
|
||||
MultMatrix(matrixOffset);
|
||||
|
||||
if ((node[0x00]&0x08)) // 4-element LOD table
|
||||
{
|
||||
lodTable = TranslateCullingAddress(node1Ptr);
|
||||
if (NULL != lodTable)
|
||||
{
|
||||
if ((node[0x03-offset]&0x20000000))
|
||||
Push(lodTable[0]&0x00FFFFFF,false); // process as culling node
|
||||
else
|
||||
{
|
||||
if (DrawModel(lodTable[0]&0x00FFFFFF))
|
||||
goto PopAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Push(node1Ptr,false);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Check for overflows and abort
|
||||
if (stackOverflow)
|
||||
{
|
||||
ErrorLog("Stack overflow in scene database!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Pop everything off the stack (ensures OpenGL matrix stack will be cleared)
|
||||
PopAll:
|
||||
while (stackTop > 0)
|
||||
Pop();
|
||||
}
|
||||
|
||||
// Draws viewports of the given priority
|
||||
void CRender3D::RenderViewport(UINT32 addr, int pri)
|
||||
{
|
||||
|
@ -1294,12 +1039,6 @@ bool CRender3D::Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned
|
|||
if (NULL == textureBuffer)
|
||||
return ErrorLog("Insufficient memory for texture decode buffer.");
|
||||
|
||||
// Allocate memory for scene stack
|
||||
stackSize = STACK_SIZE;
|
||||
stack = new(std::nothrow) UINT32[STACK_SIZE];
|
||||
if (NULL == stack)
|
||||
return ErrorLog("Insufficient memory for scene stack.");
|
||||
|
||||
// Create texture map
|
||||
glGetError(); // clear error flag
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
@ -1385,7 +1124,6 @@ CRender3D::CRender3D(void)
|
|||
vrom = NULL;
|
||||
textureRAM = NULL;
|
||||
textureBuffer = NULL;
|
||||
stack = NULL;
|
||||
|
||||
// Clear model cache pointers so we can safely destroy them if init fails
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
@ -1427,9 +1165,5 @@ CRender3D::~CRender3D(void)
|
|||
delete [] textureBuffer;
|
||||
textureBuffer = NULL;
|
||||
|
||||
if (stack != NULL)
|
||||
delete [] stack;
|
||||
stack = NULL;
|
||||
|
||||
DebugLog("Destroyed Render3D\n");
|
||||
}
|
||||
|
|
|
@ -320,19 +320,15 @@ private:
|
|||
// Texture management
|
||||
void DecodeTexture(int format, int x, int y, int width, int height);
|
||||
|
||||
// Stack management
|
||||
// Matrix stack
|
||||
void MultMatrix(UINT32 matrixOffset);
|
||||
void InitMatrixStack(UINT32 matrixBaseAddr);
|
||||
void Push(UINT32 ptr, bool pushMatrix);
|
||||
UINT32 Pop(void);
|
||||
void ClearStack(void);
|
||||
|
||||
// Scene database traversal
|
||||
bool DrawModel(UINT32 modelAddr);
|
||||
void DescendCullingNode(UINT32 addr);
|
||||
void DescendPointerList(UINT32 addr);
|
||||
void DescendNodePtr(UINT32 nodeAddr);
|
||||
void StackMachine(UINT32 nodeAddr);
|
||||
void RenderViewport(UINT32 addr, int pri);
|
||||
|
||||
// In-frame error reporting
|
||||
|
@ -362,12 +358,6 @@ private:
|
|||
// Real3D Base Matrix Pointer
|
||||
const float *matrixBasePtr;
|
||||
|
||||
// Processing stack (experimental)
|
||||
UINT32 *stack;
|
||||
int stackSize; // number of elements stack can contain
|
||||
int stackTop; // current top of stack (free spot, last element is stackTop-1)
|
||||
bool stackOverflow; // records stack overflows (cleared by ClearStack())
|
||||
|
||||
// Current viewport parameters (updated as viewports are traversed)
|
||||
GLfloat lightingParams[6];
|
||||
GLfloat fogParams[5];
|
||||
|
|
Loading…
Reference in a new issue