#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; } } } }