#include "munga.h" #include "windows.h" #pragma hdrstop #include "boxsolid.h" #include "fileutil.h" #include "origin.h" #include "linmtrx.h" #include "line.h" #include "notation.h" //############################################################################# //############################## BoxedSolid ############################# //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSolid::BoxedSolid( const ExtentBox &extents, BoxedSolid::Type type, BoxedSolid::Material material, Simulation *owner, BoxedSolid *next_solid ): TaggedBoundingBox(extents, owner) { Check_Pointer(this); solidType = type; materialType = material; nextSolid = next_solid; if (nextSolid) { Check(nextSolid); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSolid::BoxedSolid( const ExtentBox &extents, Material material, Simulation *owner, BoxedSolid *next_solid ): TaggedBoundingBox(extents, owner) { Check_Pointer(this); solidType = BlockType; materialType = material; nextSolid = next_solid; if (nextSolid) { Check(nextSolid); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSolid::~BoxedSolid() { Check_Pointer(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BoxedSolid * BoxedSolid::MakeBoxedSolid( BoxedSolidResource *boxed_solid_resource, Simulation *owner, BoxedSolid *next_solid ) { BoxedSolid *boxed_solid; switch(boxed_solid_resource->solidType) { case BoxedSolid::BlockType: boxed_solid = new BoxedSolid( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::SphereType: boxed_solid = new BoxedSphere( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::ConeType: boxed_solid = new BoxedCone( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::ReducibleBlockType: boxed_solid = new BoxedReducibleBlock( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::RampFacingNegativeZType: boxed_solid = new BoxedRampFacingNegativeZ( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::RampFacingNegativeXType: boxed_solid = new BoxedRampFacingNegativeX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::RampFacingPositiveZType: boxed_solid = new BoxedRampFacingPositiveZ( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::RampFacingPositiveXType: boxed_solid = new BoxedRampFacingPositiveX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::InvertedRampFacingNegativeZType: boxed_solid = new BoxedInvertedRampFacingNegativeZ( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::InvertedRampFacingNegativeXType: boxed_solid = new BoxedInvertedRampFacingNegativeX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::InvertedRampFacingPositiveZType: boxed_solid = new BoxedInvertedRampFacingPositiveZ( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::InvertedRampFacingPositiveXType: boxed_solid = new BoxedInvertedRampFacingPositiveX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::WedgeFacingNegativeZAndPositiveXType: boxed_solid = new BoxedWedgeFacingNegativeZAndPositiveX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::WedgeFacingNegativeZAndNegativeXType: boxed_solid = new BoxedWedgeFacingNegativeZAndNegativeX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::WedgeFacingPositiveZAndNegativeXType: boxed_solid = new BoxedWedgeFacingPositiveZAndNegativeX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::WedgeFacingPositiveZAndPositiveXType: boxed_solid = new BoxedWedgeFacingPositiveZAndPositiveX( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::XAxisCylinderType: boxed_solid = new BoxedXAxisCylinder( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::YAxisCylinderType: boxed_solid = new BoxedYAxisCylinder( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; case BoxedSolid::ZAxisCylinderType: boxed_solid = new BoxedZAxisCylinder( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid ); break; #if 0 case BoxedSolid::RightHandedTileType: { TileResource *terrain = (TileResource*)boxed_solid_resource; boxed_solid = new RightHandedTile( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid, terrain->cornerHeight ); } break; case BoxedSolid::LeftHandedTileType: { TileResource *terrain = (TileResource*)boxed_solid_resource; boxed_solid = new LeftHandedTile( boxed_solid_resource->solidExtents, boxed_solid_resource->materialType, owner, next_solid, terrain->cornerHeight ); } break; #endif default: boxed_solid = NULL; } Check(boxed_solid); return boxed_solid; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical #if DEBUG_LEVEL>0 BoxedSolid::VerifyCollision(BoxedSolidCollision &collision) #else BoxedSolid::VerifyCollision(BoxedSolidCollision &) #endif { Check(this); Check(&collision); Verify(minX <= collision.collisionSlice.minX); Verify(maxX >= collision.collisionSlice.maxX); Verify(minY <= collision.collisionSlice.minY); Verify(maxY >= collision.collisionSlice.maxY); Verify(minZ <= collision.collisionSlice.minZ); Verify(maxZ >= collision.collisionSlice.maxZ); return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSolid::ProcessCollision( BoxedSolidCollision &, const Vector3D &, BoxedSolidCollisionList *, Normal *, Scalar * ) { Fail("Unsupported mover collision type!\n"); return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedSolid::TestInstance() const { return solidType == BlockType; } //############################################################################# //########################## BoxedSolidResource ######################### //############################################################################# static const BoxedSolid::Type Left_90[BoxedSolid::SolidTypeCount]= { BoxedSolid::BlockType, BoxedSolid::SphereType, BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType, BoxedSolid::RampFacingNegativeXType, BoxedSolid::RampFacingPositiveZType, BoxedSolid::RampFacingPositiveXType, BoxedSolid::RampFacingNegativeZType, BoxedSolid::InvertedRampFacingNegativeXType, BoxedSolid::InvertedRampFacingPositiveZType, BoxedSolid::InvertedRampFacingPositiveXType, BoxedSolid::InvertedRampFacingNegativeZType, BoxedSolid::WedgeFacingNegativeZAndNegativeXType, BoxedSolid::WedgeFacingPositiveZAndNegativeXType, BoxedSolid::WedgeFacingPositiveZAndPositiveXType, BoxedSolid::WedgeFacingNegativeZAndPositiveXType, BoxedSolid::ZAxisCylinderType, BoxedSolid::YAxisCylinderType, BoxedSolid::XAxisCylinderType, BoxedSolid::LeftHandedTileType, BoxedSolid::RightHandedTileType }; static const BoxedSolid::Type Left_180[BoxedSolid::SolidTypeCount]= { BoxedSolid::BlockType, BoxedSolid::SphereType, BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType, BoxedSolid::RampFacingPositiveZType, BoxedSolid::RampFacingPositiveXType, BoxedSolid::RampFacingNegativeZType, BoxedSolid::RampFacingNegativeXType, BoxedSolid::InvertedRampFacingPositiveZType, BoxedSolid::InvertedRampFacingPositiveXType, BoxedSolid::InvertedRampFacingNegativeZType, BoxedSolid::InvertedRampFacingNegativeXType, BoxedSolid::WedgeFacingPositiveZAndNegativeXType, BoxedSolid::WedgeFacingPositiveZAndPositiveXType, BoxedSolid::WedgeFacingNegativeZAndPositiveXType, BoxedSolid::WedgeFacingNegativeZAndNegativeXType, BoxedSolid::XAxisCylinderType, BoxedSolid::YAxisCylinderType, BoxedSolid::ZAxisCylinderType, BoxedSolid::RightHandedTileType, BoxedSolid::LeftHandedTileType }; static const BoxedSolid::Type Left_270[BoxedSolid::SolidTypeCount]= { BoxedSolid::BlockType, BoxedSolid::SphereType, BoxedSolid::ConeType, BoxedSolid::ReducibleBlockType, BoxedSolid::RampFacingPositiveXType, BoxedSolid::RampFacingNegativeZType, BoxedSolid::RampFacingNegativeXType, BoxedSolid::RampFacingPositiveZType, BoxedSolid::InvertedRampFacingPositiveXType, BoxedSolid::InvertedRampFacingNegativeZType, BoxedSolid::InvertedRampFacingNegativeXType, BoxedSolid::InvertedRampFacingPositiveZType, BoxedSolid::WedgeFacingPositiveZAndPositiveXType, BoxedSolid::WedgeFacingNegativeZAndPositiveXType, BoxedSolid::WedgeFacingNegativeZAndNegativeXType, BoxedSolid::WedgeFacingPositiveZAndNegativeXType, BoxedSolid::ZAxisCylinderType, BoxedSolid::YAxisCylinderType, BoxedSolid::XAxisCylinderType, BoxedSolid::LeftHandedTileType, BoxedSolid::RightHandedTileType }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoxedSolidResource::Instance( const BoxedSolidResource &source, const Origin& origin ) { materialType = source.materialType; solidType = source.solidType; recordLength = source.recordLength; // //------------------- // Handle no rotation //------------------- // if (Close_Enough(origin.angularPosition.w, 1.0f)) { solidType = source.solidType; solidExtents = source.solidExtents; sliceExtents = source.sliceExtents; } // //------------------------------- // Test for a 180 degree rotation //------------------------------- // else if (Close_Enough(fabs(origin.angularPosition.y), 1.0f)) { solidType = Left_180[source.solidType]; solidExtents.minX = -source.solidExtents.maxX; solidExtents.maxX = -source.solidExtents.minX; solidExtents.minY = source.solidExtents.minY; solidExtents.maxY = source.solidExtents.maxY; solidExtents.minZ = -source.solidExtents.maxZ; solidExtents.maxZ = -source.solidExtents.minZ; sliceExtents.minX = -source.sliceExtents.maxX; sliceExtents.maxX = -source.sliceExtents.minX; sliceExtents.minY = source.sliceExtents.minY; sliceExtents.maxY = source.sliceExtents.maxY; sliceExtents.minZ = -source.sliceExtents.maxZ; sliceExtents.maxZ = -source.sliceExtents.minZ; } // //--------------------------------- // Handle a 90 degree left rotation //--------------------------------- // else if (Close_Enough(origin.angularPosition.w, origin.angularPosition.y)) { solidType = Left_90[source.solidType]; solidExtents.minX = source.solidExtents.minZ; solidExtents.maxX = source.solidExtents.maxZ; solidExtents.minY = source.solidExtents.minY; solidExtents.maxY = source.solidExtents.maxY; solidExtents.minZ = -source.solidExtents.maxX; solidExtents.maxZ = -source.solidExtents.minX; sliceExtents.minX = source.sliceExtents.minZ; sliceExtents.maxX = source.sliceExtents.maxZ; sliceExtents.minY = source.sliceExtents.minY; sliceExtents.maxY = source.sliceExtents.maxY; sliceExtents.minZ = -source.sliceExtents.maxX; sliceExtents.maxZ = -source.sliceExtents.minX; } // //---------------------------------- // Handle a 90 degree right rotation //---------------------------------- // else if (Close_Enough(origin.angularPosition.w, -origin.angularPosition.y)) { solidType = Left_270[source.solidType]; solidExtents.minX = -source.solidExtents.maxZ; solidExtents.maxX = -source.solidExtents.minZ; solidExtents.minY = source.solidExtents.minY; solidExtents.maxY = source.solidExtents.maxY; solidExtents.minZ = source.solidExtents.minX; solidExtents.maxZ = source.solidExtents.maxX; sliceExtents.minX = -source.sliceExtents.maxZ; sliceExtents.maxX = -source.sliceExtents.minZ; sliceExtents.minY = source.sliceExtents.minY; sliceExtents.maxY = source.sliceExtents.maxY; sliceExtents.minZ = source.sliceExtents.minX; sliceExtents.maxZ = source.sliceExtents.maxX; } // //------------------------------------------------------------------------- // Handle an arbitrary rotation. Make sure that only vertically symetrical // solids get here //------------------------------------------------------------------------- // else if ( source.solidType == BoxedSolid::YAxisCylinderType || source.solidType == BoxedSolid::ConeType || source.solidType == BoxedSolid::SphereType ) { solidType = source.solidType; Verify(source.solidExtents.minX == source.sliceExtents.minX); Verify(source.solidExtents.maxX == source.sliceExtents.maxX); Verify(source.solidExtents.minY == source.sliceExtents.minY); Verify(source.solidExtents.maxY == source.sliceExtents.maxY); Verify(source.solidExtents.minZ == source.sliceExtents.minZ); Verify(source.solidExtents.maxZ == source.sliceExtents.maxZ); Vector3D center; center.x = (source.solidExtents.minX + source.solidExtents.maxX) * 0.5f; center.y = source.solidExtents.minY; center.z = (source.solidExtents.minZ + source.solidExtents.maxZ) * 0.5f; Scalar radius = center.x - source.solidExtents.minX; LinearMatrix m; m = origin.angularPosition; Vector3D translated; translated.Multiply(center, m); solidExtents.minX = translated.x - radius; solidExtents.maxX = translated.x + radius; solidExtents.minY = source.solidExtents.minY; solidExtents.maxY = source.solidExtents.maxY; solidExtents.minZ = translated.z - radius; solidExtents.maxZ = translated.z + radius; sliceExtents = solidExtents; } // //---------------- // Otherwise, barf //---------------- // #if defined(LAB_ONLY) else { Fail("Illegal solid for a non-90 degree rotation!\n"); } #endif solidExtents.minX += origin.linearPosition.x; solidExtents.maxX += origin.linearPosition.x; solidExtents.minY += origin.linearPosition.y; solidExtents.maxY += origin.linearPosition.y; solidExtents.minZ += origin.linearPosition.z; solidExtents.maxZ += origin.linearPosition.z; sliceExtents.minX += origin.linearPosition.x; sliceExtents.maxX += origin.linearPosition.x; sliceExtents.minY += origin.linearPosition.y; sliceExtents.maxY += origin.linearPosition.y; sliceExtents.minZ += origin.linearPosition.z; sliceExtents.maxZ += origin.linearPosition.z; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void TileResource::Instance( const TileResource &source, const Origin& origin ) { BoxedSolidResource::Instance(source, origin); // //------------------------------- // Test for a 180 degree rotation //------------------------------- // if (Close_Enough(fabs(origin.angularPosition.y), 1.0f)) { cornerHeight[0] = source.cornerHeight[3]; cornerHeight[1] = source.cornerHeight[2]; cornerHeight[2] = source.cornerHeight[1]; cornerHeight[3] = source.cornerHeight[0]; } // //--------------------------------- // Handle a 90 degree left rotation //--------------------------------- // else if (Close_Enough(origin.angularPosition.w, origin.angularPosition.y)) { cornerHeight[0] = source.cornerHeight[1]; cornerHeight[1] = source.cornerHeight[3]; cornerHeight[2] = source.cornerHeight[0]; cornerHeight[3] = source.cornerHeight[2]; } // //---------------------------------- // Handle a 90 degree right rotation //---------------------------------- // else if (Close_Enough(origin.angularPosition.w, -origin.angularPosition.y)) { cornerHeight[0] = source.cornerHeight[2]; cornerHeight[1] = source.cornerHeight[0]; cornerHeight[2] = source.cornerHeight[3]; cornerHeight[3] = source.cornerHeight[1]; } } //############################################################################# ResourceDescription::ResourceID BoxedSolidResource::CreateBoxedSolidStream( const char *entry_data, ResourceFile *file, const ResourceDirectories *resource_directories, Logical convert_boxes ) { char *filename = MakePathedFilename(resource_directories->collisionDirectory, entry_data); Register_Pointer(filename); NotationFile *collision_file = new NotationFile(filename); Unregister_Pointer(filename); delete filename; Register_Object(collision_file); ResourceDescription::ResourceID collision_ID; if (collision_file->PageCount()) { // LAB_ONLY |= collision_file->IsMarkedLabOnly(); BoxedSolidList *box_solid_list = new BoxedSolidList; Register_Object(box_solid_list); int size = box_solid_list->AddBoxedSolids(collision_file); BoxedSolidResource *boxed_solid_resource = new BoxedSolidResource[size]; Register_Pointer(boxed_solid_resource); int j = 0; BoundingBoxListNode *p; for (p = box_solid_list->GetRoot(); p; p = p->GetNextNode()) { Verify(j < size); Check(p); BoxedSolid *box = (BoxedSolid *)p->GetBoundingBox(); Check(box); boxed_solid_resource[j].materialType = box->materialType; if ((box->solidType == BoxedSolid::BlockType) && (convert_boxes)) { boxed_solid_resource[j].solidType = BoxedSolid::ReducibleBlockType; } else { boxed_solid_resource[j].solidType = box->solidType; } boxed_solid_resource[j].solidExtents = *box; boxed_solid_resource[j].sliceExtents = p->solidSlice; boxed_solid_resource[j].recordLength = sizeof(boxed_solid_resource[j]); ++j; } for (p = box_solid_list->GetRoot(); p; p = p->GetNextNode()) { Check(p); BoxedSolid *box = (BoxedSolid *)p->GetBoundingBox(); Check(box); Unregister_Object(box); delete(box); } ResourceDescription *res_description = file->FindResourceDescription(entry_data, ResourceDescription::BoxedSolidStreamResourceType); if(res_description == NULL) { collision_ID = file->AddResource( entry_data, ResourceDescription::BoxedSolidStreamResourceType, 1, ResourceDescription::Preload, boxed_solid_resource, size * sizeof(BoxedSolidResource) )->resourceID; } else { collision_ID = res_description->resourceID; } Unregister_Pointer(boxed_solid_resource); delete boxed_solid_resource; Unregister_Object(box_solid_list); delete box_solid_list; } else { //---------------------------------------------- // display warning that collision file is empty //---------------------------------------------- DEBUG_STREAM << "** Collision file '" << entry_data << "' empty or not found. **" << std::endl << std::flush; //---------------------------------------------- // continue to show all missing collision files //---------------------------------------------- } Unregister_Object(collision_file); delete collision_file; return collision_ID; } //############################################################################# //########################## BoxedSolidCollision ######################## //############################################################################# static const int Cant_Occlude[BoxedSolid::SolidTypeCount]= { 0, 1<<(X_Axis|Y_Axis|Z_Axis), 1<<(X_Axis|Z_Axis), 0, 1<solidType] & (1<solidType != second->solidType ) { continue; } // //---------------------------------------------------------------------- // Figure out what face to check against, and make sure that the face of // the possibly occluding slice is nearer than the other slice //---------------------------------------------------------------------- // int face = (axis<<1) + (velocity[axis] < 0.0f); int opposite_face = face^1; if (face&1) { if (first->solidType == BoxedSolid::BlockType) { if (collisionSlice[face] <= collision.collisionSlice[face]) { continue; } } else if ( collisionSlice[opposite_face] < collision.collisionSlice[face] ) { continue; } } else { if (first->solidType == BoxedSolid::BlockType) { if (collisionSlice[face] >= collision.collisionSlice[face]) { continue; } } else if ( collisionSlice[opposite_face] > collision.collisionSlice[face] ) { continue; } } // //------------------------------------------------------------------ // Check the faces on the other axes to make sure that the occluding // object at least covers the extent of the occluded object //------------------------------------------------------------------ // for (face=0; face<6; ++face) { if ((face>>1) == axis) { continue; } if (face&1) { if (collisionSlice[face] < collision.collisionSlice[face]) { break; } } else if (collisionSlice[face] > collision.collisionSlice[face]) { break; } } // //----------------------------------------------------------------------- // If everything checked out, then List[i] occludes List[j]. Stretch the // definition of List[i] to include the slice occluded if necessary //----------------------------------------------------------------------- // if (face == 6) { face = axis<<1; if (velocity[axis] > 0.0f) { ++face; collisionSlice[face] = Max(collisionSlice[face], collision.collisionSlice[face]); } else { collisionSlice[face] = Min(collisionSlice[face], collision.collisionSlice[face]); } return True; } } return False; } //############################################################################# //######################## BoxedSolidCollisionList ###################### //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void BoxedSolidCollisionList::ReduceCollisionList(const Vector3D &velocity) { Check(this); Check(&velocity); int i,j; // //-------------------------------------------------------------------------- // 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; int collisions = GetCollisionCount(); phantomCollisions = 0; while (again && collisions>1) { again = False; // //-------------------------------------------------------------------- // Check each collision slice against the remaining slices in the list //-------------------------------------------------------------------- // for (i=0; iGetTreeVolume()->solidType != second->GetTreeVolume()->solidType ) { 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->collisionSlice[side] == second->collisionSlice[side] && first->collisionSlice[side+1] == second->collisionSlice[side+1] ) { ++matches; } else if (face<0) { face = side; } } if (matches != 2) { continue; } // //---------------------------------------------------------------- // Check to make sure that the two slices have an opposing face in // common, which will allow the slices to be fused //---------------------------------------------------------------- // if ( first->collisionSlice[face] != second->collisionSlice[face+1] && first->collisionSlice[face+1] != second->collisionSlice[face] ) { continue; } // //---------------------------------------------------------------- // Find the face to fuse, then find out which solid description to // use based upon the velocity vector //---------------------------------------------------------------- // if (first->collisionSlice[face+1] == second->collisionSlice[face]) { ++face; } BoxedSolid *original = NULL; if ( first->GetTreeVolume() != second->GetTreeVolume() && second->Occludes(*first, velocity) ) { original = first->GetTreeVolume(); first->treeVolume = second->GetTreeVolume(); } // //------------------------- // Fuse the blocks together //------------------------- // first->collisionSlice[face] = second->collisionSlice[face]; // //----------------------------------------------- // Erase the second slice from the collision list //----------------------------------------------- // for (int k=j+1; k1) { // //-------------------------- // Erase the occlusion table //-------------------------- // Logical* occluded = new Logical[collisions]; Register_Pointer(occluded); BoxedSolid **volumes = new BoxedSolid* [collisions]; Register_Pointer(volumes); for (i=0; ij) { listStart[j] = listStart[i]; } ++j; } else { volumes[++occludeds] = (BoxedSolid*)listStart[i].treeVolume; } } i = 0; while (j= point.x && minY <= point.y && minZ <= point.z && maxZ >= point.z ) { Scalar result = point.y - maxY; return Max(result, 0.0f); } else { return -1.0f; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical BoxedReducibleBlock::HitByBounded( Line *line, Scalar enters, Scalar leaves ) { Check(this); Check(line); Scalar perpendicular, drift, distance; // //-------------------- // Set up for the test //-------------------- // for (int i=0; i<6; ++i) { // //-------------------------------------------------------------------- // Figure out what axis we are dealing with, then based upon the // direction of the face, find out the distance from the origin to the // place against the normal, and find out how fast the perpendicular // distance changes with a unit movement along the line //-------------------------------------------------------------------- // int face = i; int axis = face >> 1; if (face&1) { perpendicular = line->origin[axis] - (*this)[face]; drift = line->direction[axis]; } else { perpendicular = (*this)[face] - line->origin[axis]; drift = -line->direction[axis]; } // //------------------------------------------------------------------- // If the line is parallel to the face, figure out whether or not the // line origin lies within the face's half-space //------------------------------------------------------------------- // if (Small_Enough(drift)) { if (perpendicular > 0.0f) { return False; } else { continue; } } // //-------------------------------------------------------------------- // If the drift is towards the plane's halfspace, this plane is one of // the one through which the line could enter the node //-------------------------------------------------------------------- // distance = -perpendicular / drift; if (drift < 0.0f) { if (distance > enters) { enters = distance; } if (enters > line->length) { return False; } } // //-------------------------------------------------------------------- // If the drift is towards the plane's halfspace, this plane is one of // the one through which the line could enter the node //-------------------------------------------------------------------- // else { if (distance < leaves) { leaves = distance; } if (leaves < 0.0f) { return False; } } } // //----------------------------------------------------------------------- // If we exit the loop, then make sure that we actually hit the interior, // and let the box figure out if the what happens inside it //----------------------------------------------------------------------- // if (enters <= leaves) { line->length = Max(enters, 0.0f); return True; } else { return False; } } //############################################################################# //########################### BoxedSolidList ############################ //############################################################################# //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int BoxedSolidList::AddBoxedSolids(NotationFile *notation_file) { char page_name[50]; int solidnumber = 0; int type; BoxedSolidResource boxed_solid_resource; BoxedSolid *boxed_solid; if (!notation_file->GetEntry("COLLISION", "count", &solidnumber)) { DEBUG_STREAM << "No 'COLLISION' entry!!!!!" << std::endl << std::flush; PostQuitMessage(AbortExitCodeID); } for (int j=0; j < solidnumber; ++j) { sprintf(page_name, "volume %d", j); if (!notation_file->GetEntry(page_name, "TypeNumber", &type)) { DEBUG_STREAM << "No solid at collision number : " << j << std::endl << std::flush; PostQuitMessage(AbortExitCodeID); } boxed_solid_resource.solidType = (BoxedSolid::Type)type; if (!notation_file->GetEntry(page_name, "MaterialNumber", &type)) { DEBUG_STREAM << "No material at collision number : " << j << std::endl << std::flush; PostQuitMessage(AbortExitCodeID); } boxed_solid_resource.materialType = (BoxedSolid::Material)type; int errorvalue = 0; errorvalue |= !notation_file->GetEntry(page_name, "extminX", &(boxed_solid_resource.solidExtents.minX)); errorvalue |= !notation_file->GetEntry(page_name, "extmaxX", &(boxed_solid_resource.solidExtents.maxX)); errorvalue |= !notation_file->GetEntry(page_name, "extminY", &(boxed_solid_resource.solidExtents.minY)); errorvalue |= !notation_file->GetEntry(page_name, "extmaxY", &(boxed_solid_resource.solidExtents.maxY)); errorvalue |= !notation_file->GetEntry(page_name, "extminZ", &(boxed_solid_resource.solidExtents.minZ)); errorvalue |= !notation_file->GetEntry(page_name, "extmaxZ", &(boxed_solid_resource.solidExtents.maxZ)); if ( errorvalue ) { DEBUG_STREAM << "Collision number : " << j << " does not have valid extents\n" << std::flush; PostQuitMessage(AbortExitCodeID); } errorvalue = 0; errorvalue |= !notation_file->GetEntry(page_name, "slcminX", &(boxed_solid_resource.sliceExtents.minX)); errorvalue |= !notation_file->GetEntry(page_name, "slcmaxX", &(boxed_solid_resource.sliceExtents.maxX)); errorvalue |= !notation_file->GetEntry(page_name, "slcminY", &(boxed_solid_resource.sliceExtents.minY)); errorvalue |= !notation_file->GetEntry(page_name, "slcmaxY", &(boxed_solid_resource.sliceExtents.maxY)); errorvalue |= !notation_file->GetEntry(page_name, "slcminZ", &(boxed_solid_resource.sliceExtents.minZ)); errorvalue |= !notation_file->GetEntry(page_name, "slcmaxZ", &(boxed_solid_resource.sliceExtents.maxZ)); if ( errorvalue ) { DEBUG_STREAM << "Collision number : " << j << " does not have valid slice extents\n" << std::flush; PostQuitMessage(AbortExitCodeID); } boxed_solid = BoxedSolid::MakeBoxedSolid(&boxed_solid_resource, NULL, NULL); Register_Object(boxed_solid); Add(boxed_solid, boxed_solid_resource.sliceExtents); } return solidnumber; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // #if defined(TEST_CLASS) # include "boxsolid.tcp" #endif