Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,474 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "boxsolid.h"
|
||||
#include "vector3d.h"
|
||||
|
||||
//#############################################################################
|
||||
//########################### BoxedSolidList ############################
|
||||
//#############################################################################
|
||||
|
||||
enum {
|
||||
X_Axis_Bit = 1,
|
||||
Y_Axis_Bit = 2,
|
||||
Z_Axis_Bit = 4
|
||||
};
|
||||
|
||||
enum {
|
||||
Min_Side = 0x001,
|
||||
Inside = 0x002,
|
||||
Max_Side = 0x004,
|
||||
Both_Sides = Min_Side|Max_Side,
|
||||
Shift = 3,
|
||||
X_Shift = 2 * Shift,
|
||||
Min_X_Side = Min_Side << X_Shift,
|
||||
Inside_X = Inside << X_Shift,
|
||||
Max_X_Side = Max_Side << X_Shift,
|
||||
X_Mask = Min_X_Side|Inside_X|Max_X_Side,
|
||||
Y_Shift = Shift,
|
||||
Min_Y_Side = Min_Side << Y_Shift,
|
||||
Inside_Y = Inside << Y_Shift,
|
||||
Max_Y_Side = Max_Side << Y_Shift,
|
||||
Y_Mask = Min_Y_Side|Inside_Y|Max_Y_Side,
|
||||
Z_Shift = 0,
|
||||
Min_Z_Side = Min_Side << Z_Shift,
|
||||
Inside_Z = Inside << Z_Shift,
|
||||
Max_Z_Side = Max_Side << Z_Shift,
|
||||
Z_Mask = Min_Z_Side|Inside_Z|Max_Z_Side
|
||||
};
|
||||
|
||||
int
|
||||
Legal_To_Fuse[BoxedSolid::SolidTypeCount]=
|
||||
{
|
||||
X_Axis_Bit|Y_Axis_Bit|Z_Axis_Bit, 0, 0, 0,
|
||||
X_Axis_Bit, Z_Axis_Bit, X_Axis_Bit, Z_Axis_Bit,
|
||||
X_Axis_Bit, Z_Axis_Bit, X_Axis_Bit, Z_Axis_Bit,
|
||||
Y_Axis_Bit, Y_Axis_Bit, Y_Axis_Bit, Y_Axis_Bit,
|
||||
X_Axis_Bit, Y_Axis_Bit, Z_Axis_Bit
|
||||
};
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
BoundingBoxList::Reduce()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
BoundingBoxListNode
|
||||
*i, *j, *previous;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Fuse the collision slices together into the largest possible chunks based
|
||||
// upon the collision model of each of the involved slices. Repeat until no
|
||||
// fusings were made in the last pass or only one collision slice remains
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Logical again = True;
|
||||
while (again)
|
||||
{
|
||||
again = False;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Check each collision slice against the remaining slices in the list
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
for (i=root; i; i = i->previousNode)
|
||||
{
|
||||
Check(i);
|
||||
previous = i;
|
||||
j = i->previousNode;
|
||||
while (j)
|
||||
{
|
||||
Check(j);
|
||||
//
|
||||
//-------------------------------------------------------------
|
||||
// If the model types are different, these two slices cannot be
|
||||
// fused
|
||||
//-------------------------------------------------------------
|
||||
//
|
||||
BoundingBox *first = i->boundingBox;
|
||||
BoundingBox *second = j->boundingBox;
|
||||
|
||||
//
|
||||
//----------------------------------------------------
|
||||
// Make sure that the faces on two sets of sides match
|
||||
//----------------------------------------------------
|
||||
//
|
||||
int matches = 0;
|
||||
int face = -1;
|
||||
for (int side=0; side<6; side += 2)
|
||||
{
|
||||
if (
|
||||
(*first)[side] == (*second)[side]
|
||||
&& (*first)[side+1] == (*second)[side+1]
|
||||
)
|
||||
{
|
||||
++matches;
|
||||
}
|
||||
else if (face<0)
|
||||
{
|
||||
face = side;
|
||||
}
|
||||
}
|
||||
if (matches != 2)
|
||||
{
|
||||
Next_Solid:
|
||||
previous = j;
|
||||
j = j->previousNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------
|
||||
// Check to make sure that the two solids have an opposing face in
|
||||
// common, which will allow the solids to be fused
|
||||
//----------------------------------------------------------------
|
||||
//
|
||||
if (
|
||||
(*first)[face] != (*second)[face+1]
|
||||
&& (*first)[face+1] != (*second)[face]
|
||||
)
|
||||
{
|
||||
goto Next_Solid;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------
|
||||
// Find the face to fuse, and fuse the blocks together
|
||||
//----------------------------------------------------
|
||||
//
|
||||
if ((*first)[face+1] == (*second)[face])
|
||||
{
|
||||
++face;
|
||||
}
|
||||
(*first)[face] = (*second)[face];
|
||||
|
||||
//
|
||||
//-----------------------------------------------
|
||||
// Erase the second solid from the collision list
|
||||
//-----------------------------------------------
|
||||
//
|
||||
--nodeCount;
|
||||
if (previous)
|
||||
{
|
||||
previous->previousNode = j->previousNode;
|
||||
Unregister_Object(j);
|
||||
delete(j);
|
||||
j = previous->previousNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = j->previousNode;
|
||||
Unregister_Object(j);
|
||||
delete(j);
|
||||
j = root;
|
||||
}
|
||||
again = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
BoundingBoxList::SortForTree()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
i, j;
|
||||
BoundingBoxListNode
|
||||
*p, *q;
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// Find out how many collision solids are in the list, and figure out the
|
||||
// total extent box so that we can set the traversal order correctly
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
ExtentBox map_extents;
|
||||
map_extents.minX = 65535.9999f;
|
||||
map_extents.minY = 65535.9999f;
|
||||
map_extents.minZ = 65535.9999f;
|
||||
map_extents.maxX = -65535.9999f;
|
||||
map_extents.maxY = -65535.9999f;
|
||||
map_extents.maxZ = -65535.9999f;
|
||||
for (p=root; p; p = p->previousNode)
|
||||
{
|
||||
Check(p);
|
||||
if (p->boundingBox->minX < map_extents.minX)
|
||||
{
|
||||
map_extents.minX = p->boundingBox->minX;
|
||||
}
|
||||
if (p->boundingBox->maxX > map_extents.maxX)
|
||||
{
|
||||
map_extents.maxX = p->boundingBox->maxX;
|
||||
}
|
||||
|
||||
if (p->boundingBox->minY < map_extents.minY)
|
||||
{
|
||||
map_extents.minY = p->boundingBox->minY;
|
||||
}
|
||||
if (p->boundingBox->maxY > map_extents.maxY)
|
||||
{
|
||||
map_extents.maxY = p->boundingBox->maxY;
|
||||
}
|
||||
|
||||
if (p->boundingBox->minZ < map_extents.minZ)
|
||||
{
|
||||
map_extents.minZ = p->boundingBox->minZ;
|
||||
}
|
||||
if (p->boundingBox->maxZ > map_extents.maxZ)
|
||||
{
|
||||
map_extents.maxZ = p->boundingBox->maxZ;
|
||||
}
|
||||
}
|
||||
if (
|
||||
map_extents.maxZ - map_extents.minZ
|
||||
> map_extents.maxX - map_extents.minX
|
||||
)
|
||||
{
|
||||
isXMajorAxis = False;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------
|
||||
// Allocate a scoreboard and fill it with sorting info
|
||||
//----------------------------------------------------
|
||||
//
|
||||
Verify(!scoreBoard);
|
||||
scoreBoard = new int[nodeCount * nodeCount];
|
||||
Register_Pointer(scoreBoard);
|
||||
int *score = scoreBoard;
|
||||
|
||||
boundingBoxIndex = new BoundingBox* [nodeCount];
|
||||
Register_Pointer(boundingBoxIndex);
|
||||
|
||||
for (p=root,i=0; p; p = p->previousNode,++i)
|
||||
{
|
||||
Check(p);
|
||||
BoundingBox *first = p->boundingBox;
|
||||
boundingBoxIndex[i] = first;
|
||||
for (q=root,j=0; q; q = q->previousNode,++j,++score)
|
||||
{
|
||||
|
||||
//
|
||||
//------------------------------
|
||||
// Ignore scoring against itself
|
||||
//------------------------------
|
||||
//
|
||||
Check(q);
|
||||
*score = 0;
|
||||
if (p == q)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BoundingBox *second = q->boundingBox;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Step through the three axes and set the flags showing how the
|
||||
// second solid is split up by the first solid. Make sure that if the
|
||||
// second solid completely covers the first that this inside bit is
|
||||
// set correctly
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
for (int axis = X_Axis; axis <= Z_Axis; --axis)
|
||||
{
|
||||
*score <<= Shift;
|
||||
int face = axis << 1;
|
||||
if ((*second)[face] < (*first)[face])
|
||||
{
|
||||
*score |= Min_Side;
|
||||
}
|
||||
else if ((*second)[face] < (*first)[face+1])
|
||||
{
|
||||
*score |= Inside;
|
||||
}
|
||||
if ((*second)[face+1] > (*first)[face+1])
|
||||
{
|
||||
*score |= Max_Side;
|
||||
}
|
||||
else if ((*second)[face+1] > (*first)[face])
|
||||
{
|
||||
*score |= Inside;
|
||||
}
|
||||
|
||||
if ((*score & Both_Sides) == Both_Sides)
|
||||
{
|
||||
*score |= Inside;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Create a new BoxedSolid list for results to go into, and a third in which
|
||||
// to pass the active list
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
BoundingBoxList active;
|
||||
active.root = root;
|
||||
active.nodeCount = nodeCount;
|
||||
root = NULL;
|
||||
BoundingBoxTree tree_so_far;
|
||||
|
||||
Sort(
|
||||
active,
|
||||
map_extents,
|
||||
tree_so_far
|
||||
);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
BoundingBoxList::Sort(
|
||||
BoundingBoxList &,//active,
|
||||
ExtentBox &,//map_extents,
|
||||
BoundingBoxTree &//tree_so_far
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
BoxedSolidList::Reduce()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
BoundingBoxListNode
|
||||
*i, *j, *previous;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Fuse the collision slices together into the largest possible chunks based
|
||||
// upon the collision model of each of the involved slices. Repeat until no
|
||||
// fusings were made in the last pass or only one collision slice remains
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Logical again = True;
|
||||
while (again)
|
||||
{
|
||||
again = False;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Check each collision slice against the remaining slices in the list
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
for (i=root; i; i = i->previousNode)
|
||||
{
|
||||
Check(i);
|
||||
previous = i;
|
||||
j = i->previousNode;
|
||||
while (j)
|
||||
{
|
||||
Check(j);
|
||||
//
|
||||
//-------------------------------------------------------------
|
||||
// If the model types are different, these two slices cannot be
|
||||
// fused
|
||||
//-------------------------------------------------------------
|
||||
//
|
||||
BoxedSolid *first = Cast_Object(BoxedSolid*, i->boundingBox);
|
||||
BoxedSolid *second = Cast_Object(BoxedSolid*, j->boundingBox);
|
||||
if (first->solidType != second->solidType)
|
||||
{
|
||||
Next_Solid:
|
||||
previous = j;
|
||||
j = j->previousNode;
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------
|
||||
// Make sure that the faces on two sets of sides match
|
||||
//----------------------------------------------------
|
||||
//
|
||||
int matches = 0;
|
||||
int face = -1;
|
||||
for (int side=0; side<6; side += 2)
|
||||
{
|
||||
if (
|
||||
(*first)[side] == (*second)[side]
|
||||
&& (*first)[side+1] == (*second)[side+1]
|
||||
)
|
||||
{
|
||||
++matches;
|
||||
}
|
||||
else if (face<0)
|
||||
{
|
||||
face = side;
|
||||
}
|
||||
}
|
||||
if (matches != 2)
|
||||
{
|
||||
goto Next_Solid;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------
|
||||
// Check to make sure that the two solids have an opposing face in
|
||||
// common, which will allow the solids to be fused
|
||||
//----------------------------------------------------------------
|
||||
//
|
||||
if (
|
||||
(*first)[face] != (*second)[face+1]
|
||||
&& (*first)[face+1] != (*second)[face]
|
||||
)
|
||||
{
|
||||
goto Next_Solid;
|
||||
}
|
||||
|
||||
//
|
||||
//---------------------------------------------------------------
|
||||
// Make sure that this type of solid is legal to be fused in this
|
||||
// direction
|
||||
//---------------------------------------------------------------
|
||||
//
|
||||
if (!(Legal_To_Fuse[first->solidType] & (face>>1)))
|
||||
{
|
||||
goto Next_Solid;
|
||||
}
|
||||
|
||||
//
|
||||
//----------------------------------------------------
|
||||
// Find the face to fuse, and fuse the blocks together
|
||||
//----------------------------------------------------
|
||||
//
|
||||
if ((*first)[face+1] == (*second)[face])
|
||||
{
|
||||
++face;
|
||||
}
|
||||
(*first)[face] = (*second)[face];
|
||||
|
||||
//
|
||||
//-----------------------------------------------
|
||||
// Erase the second solid from the collision list
|
||||
//-----------------------------------------------
|
||||
//
|
||||
if (previous)
|
||||
{
|
||||
previous->previousNode = j->previousNode;
|
||||
Unregister_Object(j);
|
||||
delete(j);
|
||||
j = previous->previousNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = j->previousNode;
|
||||
Unregister_Object(j);
|
||||
delete(j);
|
||||
j = root;
|
||||
}
|
||||
again = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user