//============================================================================= // Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. // // File: worldphysicsmanager.cpp // // Description: bleek // // History: May 1, 2002 - created, gmayer // //============================================================================= //======================================== // System Includes //======================================== #include #include #include #include #include #include #include #include //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include #include // just for debug prinout #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TODO // can remove // just here to hack in a light so I can see the texture damage states better #include #include //****************************************************************************** // // Global Data, Local Data, Local Classes // //****************************************************************************** WorldPhysicsManager* WorldPhysicsManager::spInstance = 0; //============================================================================= // WorldPhysicsManager::WorldPhysicsManager //============================================================================= // Description: Comment // // Parameters: () // // Return: WorldPhysicsManager // //============================================================================= WorldPhysicsManager::WorldPhysicsManager() { mCollisionDistanceCGS = 2.0f; mWorldUp.Set(0.0f, 1.0f, 0.0f); mTotalTime = 0.0f; updateFrame = 0; mLoopTime = 0.0f; sim::InitializeSimulation(MetersUnits); //SetSimUnits(); // move to bootupcontext onstart //Init(); mLastTime = 30; } //============================================================================= // WorldPhysicsManager::~WorldPhysicsManager //============================================================================= // Description: Comment // // Parameters: () // // Return: WorldPhysicsManager // //============================================================================= WorldPhysicsManager::~WorldPhysicsManager() { mSimEnvironment = 0; int i, j; for(i = 0; i < mNumCollisionAreas; i++) { for( j = 0; j < mMaxFencePerArea; j++ ) { mFences[i][j].mFenceSimState->Release(); } delete [] mCurrentStatics[i]; delete [] mCurrentAnimCollisions[i]; delete [] mCurrentUpdateAnimCollisions[i]; delete [] mFences[i]; delete [] mCurrentDynamics[i]; } delete [] mCurrentStatics; delete [] mCurrentAnimCollisions; delete [] mCurrentUpdateAnimCollisions; delete [] mFences; delete [] mFencesInEachArea; delete [] mCurrentDynamics; delete mGroundPlanePool; for( i = 0; i < mMaxFencePerArea; i++ ) { mFenceDSGResults[i]->Release(); } delete[] mFenceDSGResults; mFencePhysicsProperties->Release(); mCollisionManager->Release(); mpWorldCollisionSolverAgentManager->Release(); sim::CleanupLineDrawing (); delete [] mCollisionAreaAllocated; delete [] mCollisionAreaActive; sim::ResetSimulation (); } //============================================================================= // WorldPhysicsManager::GetInstance //============================================================================= // Description: Comment // // Parameters: () // // Return: WorldPhysicsManager // //============================================================================= WorldPhysicsManager* WorldPhysicsManager::GetInstance() { rAssert(spInstance); return spInstance; } //============================================================================= // WorldPhysicsManager::CreateInstance //============================================================================= // Description: Comment // // Parameters: () // // Return: WorldPhysicsManager // //============================================================================= WorldPhysicsManager* WorldPhysicsManager::CreateInstance() { rAssert(spInstance == 0); #ifdef RAD_GAMECUBE HeapMgr()->PushHeap( GMA_GC_VMM ); spInstance = new WorldPhysicsManager; HeapMgr()->PopHeap( GMA_GC_VMM ); #else HeapMgr()->PushHeap( GMA_PERSISTENT ); spInstance = new WorldPhysicsManager; HeapMgr()->PopHeap( GMA_PERSISTENT ); #endif rAssert(spInstance); return spInstance; } //============================================================================= // WorldPhysicsManager::Init //============================================================================= // Description: // TODO - need this? - where to call it from? // ok to call from CreateSingletons // // no - it would be called from the a context OnStart if necessary // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::Init() { mSimEnvironment = sim::SimEnvironment::GetDefaultSimEnvironment(); rAssert(mSimEnvironment); //mSimEnvironment->AddRef(); // TODO mSimEnvironment->SetCollisionDistanceCGS(mCollisionDistanceCGS); //mSimEnvironment->SetGravityCGS(0.0f, -981.0f, 0.0f); //mSimEnvironment->SetGravityCGS(0.0f, -2000.0f, 0.0f); mSimEnvironment->SetGravityCGS(0.0f, -1600.0f, 0.0f); // plum's setting //mSimEnvironment->SetGravityCGS(0.0f, -2500.0f, 0.0f); mTimerTime = 0.0f; mTimerOn = false; InitCollisionManager(); sim::SetupLineDrawing (); } //============================================================================= // WorldPhysicsManager::StartTimer //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::StartTimer() { mTimerOn = true; } //============================================================================= // WorldPhysicsManager::StopTimer //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::StopTimer() { mTimerOn = false; } //============================================================================= // WorldPhysicsManager::ResetTimer //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::ResetTimer() { mTimerTime = 0.0f; } //============================================================================= // WorldPhysicsManager::ToggleTimerState //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::ToggleTimerState() { if(mTimerOn) { mTimerOn = false; } else if(mTimerTime > 0.0f) { mTimerTime = 0.0f; } else { mTimerOn = true; } } int WorldPhysicsManager::ApplyForceToDynamics( int collisionAreaIndex, const rmt::Vector& position, float radius, const rmt::Vector& direction, float force, WorldPhysicsManager::NumObjectsHit* pObjectsHit, CollisionEntityDSGList* pCollisionEntityList ) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); int i; int numObjectsAffected = 0; float radiusSqr = radius * radius; if( pCollisionEntityList != NULL ) { // // Initialize entity list // for( i = 0; i < CollisionEntityDSGList::NUM_COLLISION_LIST_ENTITIES; i++ ) { pCollisionEntityList->collisionEntity[i] = NULL; } } for (i = 0 ; i < mMaxDynamics ; i++) { DynaPhysDSG* pDSG = mCurrentDynamics[collisionAreaIndex][i].mDynamicPhysDSG; if ( pDSG != NULL ) { rmt::Vector objPosition; rmt::Box3D boundingBox; pDSG->GetBoundingBox( &boundingBox ); rmt::Sphere boundingSphere( position, radius ); pDSG->GetPosition(&objPosition); if ( boundingBox.Intersects( boundingSphere ) ) { if ( pDSG->IsCollisionEnabled() ) { pDSG->ApplyForce( direction, force ); if( ( pCollisionEntityList != NULL ) && ( numObjectsAffected < CollisionEntityDSGList::NUM_COLLISION_LIST_ENTITIES ) ) { pCollisionEntityList->collisionEntity[numObjectsAffected] = pDSG; } ++numObjectsAffected; } } } } return numObjectsAffected; } int WorldPhysicsManager::ApplyForceToDynamicsSpherical( int collisionAreaIndex, const rmt::Vector& position, float radius, float force, CollisionEntityDSGList* pCollisionEntityList ) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); int i; int numObjectsAffected = 0; float radiusSqr = radius * radius; if( pCollisionEntityList != NULL ) { // // Initialize entity list // for( i = 0; i < CollisionEntityDSGList::NUM_COLLISION_LIST_ENTITIES; i++ ) { pCollisionEntityList->collisionEntity[i] = NULL; } } for (i = 0 ; i < mMaxDynamics ; i++) { DynaPhysDSG* pDSG = mCurrentDynamics[collisionAreaIndex][i].mDynamicPhysDSG; if ( pDSG != NULL ) { rmt::Vector objPosition; rmt::Box3D boundingBox; pDSG->GetBoundingBox( &boundingBox ); rmt::Sphere boundingSphere( position, radius ); pDSG->GetPosition(&objPosition); if ( boundingBox.Intersects( boundingSphere ) ) { if ( pDSG->IsCollisionEnabled() ) { // Calculate the vector from the position to the object rmt::Vector direction = boundingBox.Mid() - position; direction.Normalize(); pDSG->ApplyForce( direction, force ); if( ( pCollisionEntityList != NULL ) && ( numObjectsAffected < CollisionEntityDSGList::NUM_COLLISION_LIST_ENTITIES ) ) { pCollisionEntityList->collisionEntity[numObjectsAffected] = pDSG; } ++numObjectsAffected; } } } } return numObjectsAffected; } //============================================================================= // WorldPhysicsManager::InitCollisionManager //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::InitCollisionManager() { MEMTRACK_PUSH_GROUP( "WorldPhysicsManager" ); mCollisionManager = CollisionManager::GetInstance(); mCollisionManager->AddRef(); //mCollisionManager->SetCollisionDistanceCGS(mCollisionDistanceCGS); //mCollisionManager->SetCollisionManagerAttributes(CM_DetectIfMoving); // TODO - which attribute should this be? mCollisionManager->SetCollisionManagerAttributes(CM_DetectAll); // TODO - should be able to use IfMoving //mReservedCollisionAreas = 2; mReservedCollisionAreas = 0; // setup areas: // // total number of areas = max allowed number of active vehicles // + max active (human) characters {always 1 I think} // + cameras for active cars or characters // // (new) + initial reserved slots //mMaxVehicles = GetVehicleCentral()->GetMaxActiveVehicles(); //mMaxChars = GetCharacterManager()->GetMaxCharacters(); // new // jan 12, 2003 // test // values for vehicles and especially characters are now way too high // // only need slots for shit that is in existence simultaneously // 10 is probably enough mMaxVehicles = 15; // 12 - 15 would probably be enough mMaxChars = 18; mMaxCameras = MAX_PLAYERS; // this total is the number of collision areas we need + reserved // following indexing standard will be used into the collision areas array: /* reserved: 0 1 2 . . . mReservedCollisionAreas - 1 vehicles: mReservedCollisionAreas . . . . . mReservedCollisionAreas + maxVehicle - 1 characters: mReservedCollisionAreas + maxVehicle . . mReservedCollisionAreas+ maxVehicle + maxChars - 1 cameras: mReservedCollisionAreas + maxVehicle + maxChars . . mReservedCollisionAreas + maxVehicle + maxChars + maxCameras - 1 */ mNumCollisionAreas = mReservedCollisionAreas + mMaxVehicles + mMaxChars + mMaxCameras; mCollisionManager->SetNbArea(mNumCollisionAreas); // goddamn, goddamn!! mCollisionManager->SetUseExclusiveAutoPair(true); mCollisionManager->ActivateAllAreas(); #ifdef RAD_GAMECUBE HeapMgr()->PushHeap( GMA_GC_VMM ); #else HeapMgr()->PushHeap( GMA_PERSISTENT ); #endif mCollisionAreaAllocated = new bool[mNumCollisionAreas]; mCollisionAreaActive = new bool[mNumCollisionAreas]; //-------- // statics //-------- // TODO - find the right number here // TODO - different depending on thing? mMaxStatics = 30; mCurrentStatics = new StaticsInCollisionDetection*[mNumCollisionAreas]; int i,j; for(i = 0; i < mNumCollisionAreas; i++) { mCollisionAreaAllocated[i] = false; mCollisionAreaActive[i] = false; mCurrentStatics[i] = new StaticsInCollisionDetection[mMaxStatics]; for(j = 0; j < mMaxStatics; j++) { mCurrentStatics[i][j].mStaticPhysDSG = 0; mCurrentStatics[i][j].clean = false; } } //---------------- // anim collisions //---------------- // Todo: TBJ - make this value smaller. // It has to be larger because of the large radius set in CharacterManager. // When anim objects move in the DSG, we can reduce this to a smaller number. // mMaxAnimCollisions = 20; mCurrentAnimCollisions = new AnimCollisionInCollisionDetection*[mNumCollisionAreas]; for(i = 0; i < mNumCollisionAreas; i++) { mCurrentAnimCollisions[i] = new AnimCollisionInCollisionDetection[mMaxAnimCollisions]; for(j = 0; j < mMaxAnimCollisions; j++) { mCurrentAnimCollisions[i][j].mAnimCollisionEntityDSG = 0; mCurrentAnimCollisions[i][j].clean = false; } } mMaxUpdateAnimCollisions = 64; mCurrentUpdateAnimCollisions = new AnimCollisionInCollisionDetection*[mNumCollisionAreas]; for(i = 0; i < mNumCollisionAreas; i++) { mCurrentUpdateAnimCollisions[i] = new AnimCollisionInCollisionDetection[mMaxUpdateAnimCollisions]; for(j = 0; j < mMaxUpdateAnimCollisions; j++) { mCurrentUpdateAnimCollisions[i][j].mAnimCollisionEntityDSG = 0; mCurrentUpdateAnimCollisions[i][j].clean = false; } } //------- // fences //------- // TODO - find the right number here! mMaxFencePerArea = 8; mFences = new FencePieces*[mNumCollisionAreas]; mFencesInEachArea = new int[mNumCollisionAreas]; // keep a total for efficient submission/removal // new - to save memory // May 7, 2003 // // make all fences and ground planes in the pool use the same physics properties // (perhaps later change so that one for fences and one for ground planes) mFencePhysicsProperties = new sim::PhysicsProperties; mFencePhysicsProperties->AddRef(); for(i = 0; i < mNumCollisionAreas; i++) { mFences[i] = new FencePieces[mMaxFencePerArea]; for(j = 0; j < mMaxFencePerArea; j++) { // need to make collision volumes here! rmt::Vector center(0.0f, 0.0f, 0.0f); rmt::Vector o0(1.0f, 0.0f, 0.0f); rmt::Vector o1(0.0f, 1.0f, 0.0f); rmt::Vector o2(0.0f, 0.0f, 1.0f); sim::OBBoxVolume* tempOBBox = new OBBoxVolume(center, o0, o1, o2, 1.0f, 1.0f, 1.0f); mFences[i][j].mFenceSimState = (sim::ManualSimState*)(SimState::CreateManualSimState(tempOBBox)); mFences[i][j].mFenceSimState->AddRef(); mFences[i][j].mFenceSimState->GetCollisionObject()->SetManualUpdate(true); //mFences[i][j].mFenceSimState->GetCollisionObject()->SetAutoPair(true); mFences[i][j].mFenceSimState->GetCollisionObject()->SetAutoPair(false); // setting this should free the unnecessarly allocated default one: //mFences[i][j].mFenceSimState->GetCollisionObject()->SetPhysicsProperties(mFencePhysicsProperties); mFences[i][j].mFenceSimState->SetPhysicsProperties(this->mFencePhysicsProperties); // give this thing a reasonable name for debug purposes char buffy[128]; sprintf(buffy, "fence_a%d_n%d", i, j); mFences[i][j].mFenceSimState->GetCollisionObject()->SetName(buffy); mFences[i][j].mFenceSimState->mAIRefIndex = PhysicsAIRef::redBrickPhizFence; mFences[i][j].mFenceSimState->mAIRefPointer = 0; // only set if object is derived from CollisionEntityDSG mFences[i][j].mInCollision = false; mFences[i][j].mClean = false; } mFencesInEachArea[i] = 0; } // debug drawing mNumDebugFences = 0; mFenceDSGResults = new FenceEntityDSG*[mMaxFencePerArea]; for(i = 0; i < mMaxFencePerArea; i++) { mFenceDSGResults[i] = new FenceEntityDSG; mFenceDSGResults[i]->AddRef(); } //--------- // dynamics //--------- mMaxDynamics = 20; mCurrentDynamics = new DynamicsInCollisionDetection*[mNumCollisionAreas]; for(i = 0; i < mNumCollisionAreas; i++) { mCurrentDynamics[i] = new DynamicsInCollisionDetection[mMaxDynamics]; for(j = 0; j < mMaxDynamics; j++) { mCurrentDynamics[i][j].mDynamicPhysDSG = 0; mCurrentDynamics[i][j].clean = false; } } //-------------- // ground planes //-------------- mGroundPlanePool = new GroundPlanePool(mMaxDynamics * 2); // TODO - ????? how many //----------------------- // collision solver agent //----------------------- mpWorldCollisionSolverAgentManager = new WorldCollisionSolverAgentManager; mpWorldCollisionSolverAgentManager->AddRef(); mCollisionManager->GetImpulseBasedCollisionSolver()->SetCollisionSolverAgent(mpWorldCollisionSolverAgentManager); //enum DrawVolumeMethod {DrawVolumeOutline=0, DrawVolumeShape}; //sim::SetDrawVolumeMethod(DrawVolumeOutline); sim::SetDrawVolumeMethod(DrawVolumeShape); mInInterior = false; #ifdef RAD_GAMECUBE HeapMgr()->PopHeap( GMA_GC_VMM ); #else HeapMgr()->PopHeap( GMA_PERSISTENT ); #endif MEMTRACK_POP_GROUP("WorldPhysicsManager"); } //============================================================================= // WorldPhysicsManager::SuspendForInterior //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::SuspendForInterior() { mInInterior = true; } //============================================================================= // WorldPhysicsManager::ResumeForOutside //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::ResumeForOutside() { mInInterior = false; } //============================================================================= // WorldPhysicsManager::EmptyCollisionAreaIndex //============================================================================= // Description: Comment // // Parameters: (int index) // // Return: void // //============================================================================= void WorldPhysicsManager::EmptyCollisionAreaIndex(int index) { rAssert( index > WorldPhysicsManager::INVALID_COLLISION_AREA ); rAssert(mCollisionAreaAllocated[index]); // should not be trying to empty one that is not in use mCollisionManager->ResetArea(index); // this will take everything out of that area! int i; for(i = 0; i < mMaxStatics; i++) { tRefCounted::Release( mCurrentStatics[index][i].mStaticPhysDSG ); mCurrentStatics[index][i].mStaticPhysDSG = 0; mCurrentStatics[index][i].clean = false; } for(i = 0; i < mMaxAnimCollisions; i++) { tRefCounted::Release( mCurrentAnimCollisions[index][i].mAnimCollisionEntityDSG ); mCurrentAnimCollisions[index][i].mAnimCollisionEntityDSG = 0; mCurrentAnimCollisions[index][i].clean = false; } for(i = 0; i < mMaxUpdateAnimCollisions; i++) { tRefCounted::Release( mCurrentUpdateAnimCollisions[index][i].mAnimCollisionEntityDSG ); mCurrentUpdateAnimCollisions[index][i].mAnimCollisionEntityDSG = 0; mCurrentUpdateAnimCollisions[index][i].clean = false; } for(i = 0; i < mMaxFencePerArea; i++) { // don't need to add ref and release these 'cause they're only internal to the fences. mFences[index][i].mInCollision = false; } //mFencesInEachArea[index] = 0; for(i = 0; i < mMaxDynamics; i++) { if(mCurrentDynamics[index][i].mDynamicPhysDSG) { //TODO if(mCurrentDynamics[index][i].mDynamicPhysDSG->GetAIRef() != PhysicsAIRef::redBrickVehicle) { mCurrentDynamics[index][i].mDynamicPhysDSG->FreeGroundPlane(); // in case it still has one // this is also where the ground plane collision object will be disabled if // there are no more refs } tRefCounted::Release( mCurrentDynamics[index][i].mDynamicPhysDSG ); mCurrentDynamics[index][i].mDynamicPhysDSG = 0; mCurrentDynamics[index][i].clean = false; } } // TODO - setup some sort of enable/disable interface also? } //============================================================================= // WorldPhysicsManager::FreeCollisionAreaIndex //============================================================================= // Description: Comment // // Parameters: (int index) // // Return: void // //============================================================================= void WorldPhysicsManager::FreeCollisionAreaIndex(int index) { rAssert( index > WorldPhysicsManager::INVALID_COLLISION_AREA ); rAssert(mCollisionAreaAllocated[index]); // should not be trying to free up one that is not in use EmptyCollisionAreaIndex( index ); mCollisionAreaAllocated[index] = false; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// void WorldPhysicsManager::FreeAllCollisionAreaIndicies() { int index = 0; for(; index(obj); // Character* character= dynamic_cast(obj); Vehicle* vehicle = NULL; Character* character = NULL; if ( obj->GetAIRef() == PhysicsAIRef::NPCharacter || obj->GetAIRef() == PhysicsAIRef::PlayerCharacter ) { rAssert( dynamic_cast< Character* >( obj ) ); character = static_cast< Character*>( obj ) ; } else if ( obj->GetAIRef() == PhysicsAIRef::redBrickVehicle ) { rAssert( dynamic_cast< Vehicle* >( obj )); vehicle = static_cast< Vehicle*>( obj ); } else { rAssert( dynamic_cast< Character* >( obj )==false); rAssert( dynamic_cast< Vehicle* >( obj )==false); } for(i = 0; i < mNumCollisionAreas; i++) { if(vehicle && (i == vehicle->mCollisionAreaIndex)) { continue; } if(character && (i == character->GetCollisionAreaIndex())) { continue; } if(!mCollisionAreaAllocated[i]) { continue; } int j; for(j = 0; j < mMaxDynamics; j++) { if(mCurrentDynamics[i][j].mDynamicPhysDSG == obj) { mCollisionManager->RemoveCollisionObject(obj->GetSimState()->GetCollisionObject(), i); // only deal with ground plane here if the incoming object is not a car if(!(vehicle)) { int groundPlaneIndex = mCurrentDynamics[i][j].mDynamicPhysDSG->GetGroundPlaneIndex(); if(groundPlaneIndex != -1) // should never be false... { sim::CollisionObject* gpCollObj = mGroundPlanePool->GetSimState(groundPlaneIndex)->GetCollisionObject(); mCollisionManager->RemoveCollisionObject(gpCollObj, i); mCurrentDynamics[i][j].mDynamicPhysDSG->FreeGroundPlane(); // this decrements the groundplaneref, but we still need to take it out of } } mCurrentDynamics[i][j].mDynamicPhysDSG = 0; mCurrentDynamics[i][j].clean = false; obj->Release(); } } } } //============================================================================= // WorldPhysicsManager::OnQuitLevel //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::OnQuitLevel() { // make sure ground plane pool has been properly free'd up if(!(mGroundPlanePool->FreeAllGroundPlanes())) { // there was some ground planes that were not yet free'd when this was called! rAssertMsg(false, "not all the ground planes were free'd by their dynamic object owners! bad dynamic objects!\n"); } } //============================================================================= // WorldPhysicsManager::GetCameraCollisionAreaIndex //============================================================================= // Description: Comment // // Parameters: () // // Return: int // //============================================================================= int WorldPhysicsManager::GetCameraCollisionAreaIndex() { // moved to member data //int maxVehicles = GetVehicleCentral()->GetMaxActiveVehicles(); //int maxChars = MAX_PLAYERS; //int maxCameras = MAX_PLAYERS; int start = mReservedCollisionAreas + mMaxVehicles + mMaxChars; int end = mReservedCollisionAreas + mMaxVehicles + mMaxChars + mMaxCameras - 1; int i; for(i = start; i <= end; i++) { // look for first free index if(mCollisionAreaAllocated[i]) { continue; } else { mCollisionAreaAllocated[i] = true; return i; } } rReleaseAssertMsg( 0, "not enough camera collision indices\n" ); return WorldPhysicsManager::INVALID_COLLISION_AREA; } //============================================================================= // WorldPhysicsManager::GetVehicleCollisionAreaIndex //============================================================================= // Description: Comment // // Parameters: () // // Return: int // //============================================================================= int WorldPhysicsManager::GetVehicleCollisionAreaIndex() { //int maxVehicles = GetVehicleCentral()->GetMaxActiveVehicles(); int start = mReservedCollisionAreas; int end = mReservedCollisionAreas + mMaxVehicles - 1; int i; for(i = start; i <= end; i++) { // look for first free index if(mCollisionAreaAllocated[i]) { continue; } else { mCollisionAreaAllocated[i] = true; return i; } } rReleaseAssertMsg( 0, "not enough vehicle collision indices\n" ); return WorldPhysicsManager::INVALID_COLLISION_AREA; } //============================================================================= // WorldPhysicsManager::GetCharacterCollisionAreaIndex //============================================================================= // Description: Comment // // Parameters: () // // Return: int // //============================================================================= int WorldPhysicsManager::GetCharacterCollisionAreaIndex() { //int maxVehicles = GetVehicleCentral()->GetMaxActiveVehicles(); //int maxChars = MAX_PLAYERS; int start = mReservedCollisionAreas + mMaxVehicles; int end = mReservedCollisionAreas + mMaxVehicles + mMaxChars - 1; int i; for(i = start; i <= end; i++) { // look for first free index if(mCollisionAreaAllocated[i]) { continue; } else { mCollisionAreaAllocated[i] = true; return i; } } rReleaseAssertMsg( 0, "not enough character collision indices\n" ); return WorldPhysicsManager::INVALID_COLLISION_AREA; } //============================================================================= // WorldPhysicsManager::DestroyInstance //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::DestroyInstance() { rAssert(spInstance); // TODO - Release() collision manager delete(GMA_PERSISTENT, spInstance); spInstance = NULL; } //============================================================================= // WorldPhysicsManager::SetSimUnits //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= /* void WorldPhysicsManager::SetSimUnits() { float LSCALE = 0.01f; //float MSCALE = 0.001f; float MSCALE = 1.0f; float TSCALE = 1.0f; SimUnitsManager um; um.SetUnits(LSCALE, MSCALE, TSCALE); } */ //============================================================================= // WorldPhysicsManager::Update //============================================================================= // Description: Comment // // Parameters: (unsigned int timeDeltaSeconds) // // Return: void // //============================================================================= void WorldPhysicsManager::Update(unsigned int timeDeltaMilliSeconds) { BEGIN_PROFILE("WorldPhysicsManager::Update") BEGIN_PROFILE("Vehicle Submits") GetVehicleCentral()->SubmitStatics(); GetVehicleCentral()->SubmitAnimCollisions(); GetVehicleCentral()->SubmitDynamics(); END_PROFILE("Vehicle Submits") BEGIN_PROFILE("Character Submits") GetCharacterManager()->SubmitStatics(); GetCharacterManager()->SubmitAnimCollisions(); // both collision and update I assume GetCharacterManager()->SubmitDynamics(); END_PROFILE("Character Submits") BEGIN_PROFILE("Cam Submits") GetSuperCamManager()->SubmitStatics(); END_PROFILE("Cam Submits") BEGIN_PROFILE("Update Ground") UpdateSimluatingDynamicObjectGroundPlanes(); END_PROFILE("Update Ground") // new substep logic - nbrooke 12/7/03 // // we want to try to minimize it ticking over into two substep mode unless it absolutly neccesary // and try to run a 30fps on the ps2 all the time therefore I have // 1) upped the threshold for going to two substeps to 35 ms from 32ms // 2) only go into multiple substeps if we get two consecutive frames over the threshold or // one frame WAY over the threshold unsigned numSubsteps = 1; if(((mLastTime > 35) && (timeDeltaMilliSeconds > 35)) || (timeDeltaMilliSeconds > 50)) { numSubsteps = (timeDeltaMilliSeconds + 34) / 35; } mLastTime = timeDeltaMilliSeconds; float substep = (float(timeDeltaMilliSeconds) * 0.001f) / float(numSubsteps); float dt = static_cast(timeDeltaMilliSeconds) * 0.001f; // cap if(numSubsteps > 10) { rReleasePrintf("\nhit 10 substeps!\n"); numSubsteps = 10; } mLoopTime = dt; if(mTimerOn) { mTimerTime += dt; } BEGIN_PROFILE("WorldPhysicsManager::PreSubstepUpdate") GetVehicleCentral()->PreSubstepUpdate(dt); END_PROFILE("WorldPhysicsManager::PreSubstepUpdate") BEGIN_PROFILE("PreSim") GetCharacterManager( )->PreSimUpdate( dt ); END_PROFILE("PreSim") bool firstSubstep = true; //while(countDown > timestep)// * 1.5f) for(unsigned i = 0; i < numSubsteps; i++) { // do shit WorldSimSubstepGuts(substep, firstSubstep); firstSubstep = false; } BEGIN_PROFILE("VehiclePost") GetVehicleCentral()->PostSubstepUpdate(dt); END_PROFILE("VehiclePost") BEGIN_PROFILE("CharPost") GetCharacterManager()->PostSimUpdate( dt ); END_PROFILE("CharPost") END_PROFILE("WorldPhysicsManager::Update") BEGIN_PROFILE("Phys DebugInfo") DebugInfoDisplay(); END_PROFILE("Phys DebugInfo") } //============================================================================= // WorldPhysicsManager::DebugInfoDisplay //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::DebugInfoDisplay() { // maybe "Display" is a bit deceiving. #ifdef DEBUGINFO_ENABLED DEBUGINFO_PUSH_SECTION( "Vehicle Shit" ); // just display the vehicles position // whichever vehicle player is driving Avatar* playerAvatar = GetAvatarManager()->GetAvatarForPlayer(0); Vehicle* playerVehicle = 0; if(playerAvatar) { playerVehicle = playerAvatar->GetVehicle(); if(playerVehicle) { float x = 0.0f; float y = 0.0f; float z = 0.0f; rmt::Vector pos = playerVehicle->GetPosition(); x = pos.x; y = pos.y; z = pos.z; char buffy[128]; sprintf( buffy, "position - x: %.2f y: %.2f z: %.2f", x, y, z); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? float life = playerVehicle->GetVehicleLifePercentage(playerVehicle->mHitPoints); sprintf( buffy, "damage inc. - %.3f", 1.0f - life); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? if(playerVehicle->mVehicleState == VS_NORMAL) { sprintf( buffy, "VS_NORMAL"); } else if(playerVehicle->mVehicleState == VS_EBRAKE_SLIP) { sprintf( buffy, "VS_EBRAKE_SLIP"); } else { sprintf( buffy, "VS_SLIP"); } DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? /* if(playerVehicle->mLosingTractionDueToAccel) { sprintf(buffy, "LOSING TRACTION DUE TO ACCELERATION!!"); } else { sprintf(buffy, "unmodified traction"); } DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? if(playerVehicle->mLoco == VL_PHYSICS) // I think this will always be the case { sprintf(buffy, "currentSteeringForce: %.2f", playerVehicle->mPhysicsLocomotion->mCurrentSteeringForce); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? } */ sprintf(buffy, "wheel turn angle unmodified input: %.2f", playerVehicle->mUnmodifiedInputWheelTurnAngle); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "wheel turn angle normalized: %.2f", playerVehicle->mWheelTurnAngleInputValue); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "wheel turn angle: %.2f", playerVehicle->mWheelTurnAngle); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "kmh: %.2f", playerVehicle->mSpeedKmh); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "ebrake: %.2f", playerVehicle->mEBrake); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "gas: %.2f", playerVehicle->mGas); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? sprintf(buffy, "timer: %.3f", mTimerTime); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? /* sprintf(buffy, "speed burst timer: %.3f", playerVehicle->mSpeedBurstTimer); DEBUGINFO_ADDSCREENTEXT( buffy ); DEBUGINFO_ADDSCREENTEXT( "" ); //? if(playerVehicle->mDoSpeedBurst) { sprintf(buffy, "doing speed burst!"); } else { sprintf(buffy, "not doing speed burst"); } */ } } DEBUGINFO_POP_SECTION(); if(playerVehicle) { char temp[128]; DebugInfo::GetInstance()->Push( "Vehicle Terrain Type" ); sprintf( temp, "average for vehicle: %d. %sside.", playerVehicle->mTerrainType, playerVehicle->mInterior ? "In" : "Out" ); DebugInfo::GetInstance()->AddScreenText( temp, tColour( 25, 150, 125 ) ); sprintf( temp, "wheel 0: %d", playerVehicle->mPhysicsLocomotion->mTerrainIntersectCache[0].mTerrainType); DebugInfo::GetInstance()->AddScreenText( temp, tColour( 25, 150, 125 ) ); sprintf( temp, "wheel 1: %d", playerVehicle->mPhysicsLocomotion->mTerrainIntersectCache[1].mTerrainType); DebugInfo::GetInstance()->AddScreenText( temp, tColour( 25, 150, 125 ) ); sprintf( temp, "wheel 2: %d", playerVehicle->mPhysicsLocomotion->mTerrainIntersectCache[2].mTerrainType); DebugInfo::GetInstance()->AddScreenText( temp, tColour( 25, 150, 125 ) ); sprintf( temp, "wheel 3: %d", playerVehicle->mPhysicsLocomotion->mTerrainIntersectCache[3].mTerrainType); DebugInfo::GetInstance()->AddScreenText( temp, tColour( 25, 150, 125 ) ); DebugInfo::GetInstance()->Pop(); /* DebugInfo::GetInstance()->Push( "Player Vehicle Collision Info" ); int colindex = playerVehicle->mCollisionAreaIndex; sprintf( temp, "number of collision pairs in player collision area: %d", this->mCollisionManager->GetCollisionObjectPairList(colindex)->ArraySize()); DEBUGINFO_ADDSCREENTEXT( temp ); DEBUGINFO_ADDSCREENTEXT( "" ); //? DebugInfo::GetInstance()->Pop(); */ } #endif // DEBUGINFO_ENABLED } //============================================================================= // WorldPhysicsManager::WorldSimSubstepGuts //============================================================================= // Description: Comment // // Parameters: (float dt) // // Return: void // //============================================================================= void WorldPhysicsManager::WorldSimSubstepGuts(float dt, bool firstSubstep) { BEGIN_PROFILE("WorldSimSubstepGuts") mTotalTime += dt; updateFrame++; BEGIN_PROFILE("VC::PreCollisionPrep") if(!mInInterior) { GetVehicleCentral()->PreCollisionPrep(dt, firstSubstep); } END_PROFILE("VC::PreCollisionPrep") BEGIN_PROFILE("CharMgr::PreSimUpdate") GetCharacterManager()->PreSubstepUpdate( dt ); END_PROFILE("CharMgr::PreSimUpdate") BEGIN_PROFILE("ABMgr::Update") GetActionButtonManager( )->Update( dt ); END_PROFILE("ABMgr::Update") // BEGIN_PROFILE("SuperCamMgr::PreCollPrep") // GetSuperCamManager()->PreCollisionPrep(); // END_PROFILE("SuperCamMgr::PreCollPrep") BEGIN_PROFILE("ResetCollisionFlags") mpWorldCollisionSolverAgentManager->ResetCollisionFlags(); END_PROFILE("ResetCollisionFlags") BEGIN_PROFILE("DetectCollisions") bool printOut = false; mCollisionManager->ClearCollisions(); mCollisionManager->DetectCollision(dt, mTotalTime, printOut ); mCollisionManager->SolveCollision(dt, mTotalTime); END_PROFILE("DetectCollisions") BEGIN_PROFILE("GetVehicleCentral()->Update") GetVehicleCentral()->Update(dt); END_PROFILE("GetVehicleCentral()->Update") BEGIN_PROFILE("GetCharacterManager()->Update") GetCharacterManager()->Update( dt ); END_PROFILE("GetCharacterManager()->Update") BEGIN_PROFILE("GetCharacterManager()->PostSimUpdate") GetCharacterManager()->PostSubstepUpdate(dt); END_PROFILE("GetCharacterManager()->PostSimUpdate") //Update the position of the super camers BEGIN_PROFILE("GetSuperCamManager()->Update") GetSuperCamManager()->Update( rmt::FtoL(dt * 1000.0f), firstSubstep ); END_PROFILE("GetSuperCamManager()->Update") //Detect collisions on the new position of the super camera int area = GetSuperCamManager()->GetSCC( 0 )->mCollisionAreaIndex; mCollisionManager->ClearCollisions(); BEGIN_PROFILE("SuperCamMgr::PreCollPrep") GetSuperCamManager()->PreCollisionPrep(); END_PROFILE("SuperCamMgr::PreCollPrep") mCollisionManager->DetectCollision( area, dt, mTotalTime, printOut ); mCollisionManager->SolveCollision( area, dt, mTotalTime ); //Correct the position of the super camera GetSuperCamManager()->GetSCC( 0 )->UpdateForPhysics( rmt::FtoL(dt * 1000.0f) ); END_PROFILE("WorldSimSubstepGuts") } //============================================================================= // WorldPhysicsManager::DisplayCollisionObjectsExceptVehicleInArea //============================================================================= // Description: Comment // // Parameters: (int area) // // Return: void // //============================================================================= void WorldPhysicsManager::DisplayFencesInArea(int area) { rAssert( area > WorldPhysicsManager::INVALID_COLLISION_AREA ); int i; for(i = 0; i < mMaxFencePerArea; i++) { if(mFences[area][i].mInCollision) { sim::ManualSimState* mss = mFences[area][i].mFenceSimState; sim::DrawCollisionObject(mss->GetCollisionObject()); } } for(i = 0; i < mNumDebugFences; i++) { // debug draw it! mFenceDSGResults[i]->Display(); } } //============================================================================= // WorldPhysicsManager::SubmitStaticsPseudoCallback //============================================================================= // Description: Comment // // Parameters: (rmt::Vector& position, float radius, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::SubmitStaticsPseudoCallback(rmt::Vector& position, float radius, int collisionAreaIndex, sim::SimState* callerSimState, bool allowAutoPairing) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); BEGIN_PROFILE( "SubmitStaticsPseudoCallback" ); ReserveArray staticPhysDSGList; int i; for(i = 0; i < mMaxStatics; i++) { mCurrentStatics[collisionAreaIndex][i].clean = false; // probably slower to check if there's // even something pointed to than just // to do this } BEGIN_PROFILE( "FindStaticPhysElems" ); GetIntersectManager()->FindStaticPhysElems(position, radius, staticPhysDSGList); END_PROFILE( "FindStaticPhysElems" ); int numResults = staticPhysDSGList.mUseSize; // !!!! // temp // // TODO // hmmm... what to do here? // pick different max or try and prioritize further? // // also TODO - need different maxes for different lists if(numResults > mMaxStatics) { numResults = mMaxStatics; rDebugPrintf("\n!!! too many statics !!!\n"); } for(i = 0; i < numResults; i++) { // go through results and submit to collision. // first see if already in our list StaticPhysDSG* curr = staticPhysDSGList[i]; int j; bool alreadyIn = false; for(j = 0; j < mMaxStatics; j++) { if(mCurrentStatics[collisionAreaIndex][j].mStaticPhysDSG == curr) { // this one already in list mCurrentStatics[collisionAreaIndex][j].clean = true; alreadyIn = true; break; } } if(!alreadyIn) { // add to our list and to collision manager // // look for first available slot int k; for(k = 0; k < mMaxStatics; k++) { if(mCurrentStatics[collisionAreaIndex][k].mStaticPhysDSG == 0) { // here is a slot mCurrentStatics[collisionAreaIndex][k].mStaticPhysDSG = curr; mCurrentStatics[collisionAreaIndex][k].mStaticPhysDSG->AddRef(); mCurrentStatics[collisionAreaIndex][k].clean = true; sim::CollisionObject* currCollObj = curr->mpSimState()->GetCollisionObject(); BEGIN_PROFILE( "AddCollisionObject" ); if(1)//allowAutoPairing) { currCollObj->SetAutoPair(true); } else { currCollObj->SetAutoPair(false); } mCollisionManager->AddCollisionObject(currCollObj, collisionAreaIndex); //if(!allowAutoPairing) { mCollisionManager->AddPair(currCollObj, callerSimState->GetCollisionObject(), collisionAreaIndex); } END_PROFILE( "AddCollisionObject" ); break; } } rAssert(k < mMaxStatics); // TODO - deal with no available slots.... } } // now look through remaining list and remove unclean for(i = 0; i < mMaxStatics; i++) { if(mCurrentStatics[collisionAreaIndex][i].mStaticPhysDSG != 0 && mCurrentStatics[collisionAreaIndex][i].clean == false) { BEGIN_PROFILE( "RemoveCollisionObject" ); mCollisionManager->RemoveCollisionObject(mCurrentStatics[collisionAreaIndex][i].mStaticPhysDSG->mpSimState()->GetCollisionObject(), collisionAreaIndex); END_PROFILE( "RemoveCollisionObject" ); mCurrentStatics[collisionAreaIndex][i].mStaticPhysDSG->Release(); mCurrentStatics[collisionAreaIndex][i].mStaticPhysDSG = 0; mCurrentStatics[collisionAreaIndex][i].clean = false; // this is redundant } } END_PROFILE( "SubmitStaticsPseudoCallback" ); } //============================================================================= // WorldPhysicsManager::SubmitAnimCollisionsPseudoCallback //============================================================================= // Description: Comment // // Parameters: (rmt::Vector& position, float radius, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::SubmitAnimCollisionsPseudoCallback(rmt::Vector& position, float radius, int collisionAreaIndex, sim::SimState* callerSimState) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); ReserveArray animCollisionEntityDSGList; int i; for(i = 0; i < mMaxAnimCollisions; i++) { mCurrentAnimCollisions[collisionAreaIndex][i].clean = false; } GetIntersectManager()->FindAnimPhysElems(position, radius, animCollisionEntityDSGList); int numResults = animCollisionEntityDSGList.mUseSize; if(numResults > mMaxAnimCollisions) { numResults = mMaxAnimCollisions; rDebugPrintf("\n!!! too many animating collision objects - goddamn !!!\n"); } for(i = 0; i < numResults; i++) { // go through results and submit to collision. // first see if already in our list AnimCollisionEntityDSG* curr = animCollisionEntityDSGList[i]; int j; bool alreadyIn = false; for(j = 0; j < mMaxAnimCollisions; j++) { if(mCurrentAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG == curr) { // this one already in list mCurrentAnimCollisions[collisionAreaIndex][j].clean = true; alreadyIn = true; break; } } if(!alreadyIn) { // add to our list and to collision manager // // look for first available slot int k; for(k = 0; k < mMaxAnimCollisions; k++) { if(mCurrentAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG == 0) { // here is a slot mCurrentAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG = curr; mCurrentAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG->AddRef( ); mCurrentAnimCollisions[collisionAreaIndex][k].clean = true; sim::CollisionObject* currCollObj = curr->GetSimState()->GetCollisionObject(); currCollObj->SetAutoPair(false); mCollisionManager->AddCollisionObject(currCollObj, collisionAreaIndex); mCollisionManager->AddPair(currCollObj, callerSimState->GetCollisionObject(), collisionAreaIndex); break; } } rAssert(k < mMaxAnimCollisions); // TODO - deal with no available slots.... } } // now look through remaining list and remove unclean for(i = 0; i < mMaxAnimCollisions; i++) { if(mCurrentAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG != 0 && mCurrentAnimCollisions[collisionAreaIndex][i].clean == false) { mCollisionManager->RemoveCollisionObject(mCurrentAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG->GetSimState()->GetCollisionObject(), collisionAreaIndex); mCurrentAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG->Release( ); mCurrentAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG = 0; mCurrentAnimCollisions[collisionAreaIndex][i].clean = false; // this is redundant } } } //============================================================================= // WorldPhysicsManager::SubmitAnimCollisionsForUpdateOnly //============================================================================= // Description: Comment // // Parameters: (rmt::Vector& position, float radius, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::SubmitAnimCollisionsForUpdateOnly(rmt::Vector& position, float radius, int collisionAreaIndex) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); ReserveArray animCollisionEntityDSGList; int i; for(i = 0; i < mMaxUpdateAnimCollisions; i++) { mCurrentUpdateAnimCollisions[collisionAreaIndex][i].clean = false; } GetIntersectManager()->FindAnimPhysElems(position, radius, animCollisionEntityDSGList); int numResults = animCollisionEntityDSGList.mUseSize; if(numResults > mMaxUpdateAnimCollisions) { numResults = mMaxUpdateAnimCollisions; rDebugPrintf("\n!!! too many animating collision objects - goddamn !!!\n"); } for(i = 0; i < numResults; i++) { // go through results and submit to collision. // first see if already in our list AnimCollisionEntityDSG* curr = animCollisionEntityDSGList[i]; int j; bool alreadyIn = false; for(j = 0; j < mMaxUpdateAnimCollisions; j++) { if(mCurrentUpdateAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG == curr) { // this one already in list mCurrentUpdateAnimCollisions[collisionAreaIndex][j].clean = true; alreadyIn = true; break; } } if(!alreadyIn) { // add to our list and to collision manager // // look for first available slot int k; for(k = 0; k < mMaxUpdateAnimCollisions; k++) { if(mCurrentUpdateAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG == 0) { // here is a slot mCurrentUpdateAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG = curr; // Hang on to this object. // mCurrentUpdateAnimCollisions[collisionAreaIndex][k].mAnimCollisionEntityDSG->AddRef( ); mCurrentUpdateAnimCollisions[collisionAreaIndex][k].clean = true; break; } } rAssert(k < mMaxUpdateAnimCollisions); // TODO - deal with no available slots.... } } // now look through remaining list and remove unclean for(i = 0; i < mMaxUpdateAnimCollisions; i++) { if(mCurrentUpdateAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG != 0 && mCurrentUpdateAnimCollisions[collisionAreaIndex][i].clean == false) { // Let this thing go. // mCurrentUpdateAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG->Release( ); mCurrentUpdateAnimCollisions[collisionAreaIndex][i].mAnimCollisionEntityDSG = 0; mCurrentUpdateAnimCollisions[collisionAreaIndex][i].clean = false; // this is redundant } } } //============================================================================= // WorldPhysicsManager::SubmitDynamicsPseudoCallback //============================================================================= // Description: Comment // // Parameters: (rmt::Vector& position, float radius, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::SubmitDynamicsPseudoCallback(rmt::Vector& position, float radius, int collisionAreaIndex, sim::SimState* callerSimState, bool allowAutoPairing) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); // hmmm... // safe to make this an InstDynaPhysDSG list?? - doesn't compile ReserveArray dynamicsPhysDSGList; int i; for(i = 0; i < mMaxDynamics; i++) { mCurrentDynamics[collisionAreaIndex][i].clean = false; // probably slower to check if there's // even something pointed to than just // to do this } // this is just commented out until it exists GetIntersectManager()->FindDynaPhysElems(position, radius, dynamicsPhysDSGList); int numResults = dynamicsPhysDSGList.mUseSize; if(numResults > 1) { int stophere = 1; } // TODO // hmmm... what to do here? if(numResults > mMaxDynamics) { numResults = mMaxDynamics; rDebugPrintf("\n!!! too many dynamics returned from query !!!\n"); } for(i = 0; i < numResults; i++) { // go through results and submit to collision. // first see if already in our list DynaPhysDSG* curr = dynamicsPhysDSGList[i]; // temp // // this actually might be the way to do it? //if(curr == caller) if((curr->mpSimState() == callerSimState) || (curr->mpSimState() == NULL)) { continue; } // new test // just for Cary if(callerSimState->mAIRefIndex == PhysicsAIRef::CameraSphere) { if( curr->mpSimState()->mAIRefIndex != PhysicsAIRef::redBrickVehicle && curr->mpSimState()->mAIRefIndex != PhysicsAIRef::NPCharacter && curr->mpSimState()->mAIRefIndex != PhysicsAIRef::PlayerCharacter ) { continue; } } // not optimization further below // // only gonna pair "submitters" with ourselves // // this logic here is to see if the current "submitter" is trying to pair itself against another "submitter" vehicle we already called earlier, that // already set up this pair if(callerSimState->mAIRefIndex == PhysicsAIRef::redBrickVehicle && curr->mpSimState()->mAIRefIndex == PhysicsAIRef::redBrickVehicle) { // April 22, 2003 // problem when cars that are calling this are very close to each other // // many duplicate pairs put in more than one collision area // // the fastest, most optimal check we can do to minimize this is: // (first re-order the vehicle calls to this to make sure VT_USER called first) // then, if we are a car, and return a car, and either it's a VT_USER or it's and AI with // a lower vehicle central index than us, then skipt it - they've already submitted us, and autopaird all round! Vehicle* submittingVehicle = (Vehicle*)(callerSimState->mAIRefPointer); Vehicle* submittedVehicle = (Vehicle*)(curr->mpSimState()->mAIRefPointer); rTuneAssert(submittingVehicle->mVehicleCentralIndex != -1); rTuneAssert(submittedVehicle->mVehicleCentralIndex != -1); if(submittingVehicle->mVehicleType == VT_USER) { if(submittedVehicle->mVehicleType == VT_USER) { if(submittingVehicle->mVehicleCentralIndex > submittedVehicle->mVehicleCentralIndex) { // both user vehicles, but... // the submitted vehicle has been called first, so it wins continue; } } } else { // not a user vehicle if(submittedVehicle->mVehicleType == VT_USER) { // it has already added us continue; } else if(submittingVehicle->mVehicleType == VT_AI) { if(submittingVehicle->mVehicleCentralIndex > submittedVehicle->mVehicleCentralIndex) { // the submitted vehicle has been called first, so it wins continue; } } } } int j; bool alreadyIn = false; for(j = 0; j < mMaxDynamics; j++) { if(mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG == curr) { // this one already in list mCurrentDynamics[collisionAreaIndex][j].clean = true; alreadyIn = true; break; } } if(!alreadyIn) { // add to our list and to collision manager // // look for first available slot int k; for(k = 0; k < mMaxDynamics; k++) { if(mCurrentDynamics[collisionAreaIndex][k].mDynamicPhysDSG == 0) { // here is a slot mCurrentDynamics[collisionAreaIndex][k].mDynamicPhysDSG = curr; mCurrentDynamics[collisionAreaIndex][k].mDynamicPhysDSG->AddRef( ); mCurrentDynamics[collisionAreaIndex][k].clean = true; sim::CollisionObject* currCollObj = curr->mpSimState()->GetCollisionObject(); // final, simplest possible optimization // // don't autopair dynamics period // any dynamic we submit only pairs with us! // // who knows what else this thing will do in it's own area (if it has one), so just in case turn // turn flag back on after // only pair with us // if(allowAutoPairing && curr->mpSimState()->mAIRefIndex != PhysicsAIRef::redBrickVehicle) { currCollObj->SetAutoPair(true); } else { currCollObj->SetAutoPair(false); } mCollisionManager->AddCollisionObject(currCollObj, collisionAreaIndex); //if(!allowAutoPairing || curr->mpSimState()->mAIRefIndex == PhysicsAIRef::redBrickVehicle) { mCollisionManager->AddPair(currCollObj, callerSimState->GetCollisionObject(), collisionAreaIndex); } /* // new?? // is this gonna work, and work well? //!! // only do this for the player character! int l; for(l = 0; l < this->mMaxStatics; l++) { if(mCurrentStatics[collisionAreaIndex][l].mStaticPhysDSG) { // there's one there... // make sure we are paired with it mCollisionManager->AddPair(currCollObj, mCurrentStatics[collisionAreaIndex][l].mStaticPhysDSG->mpSimState()->GetCollisionObject(), collisionAreaIndex); } } for(l = 0; l < this->mMaxFencePerArea; l++) { if(mFences[collisionAreaIndex][l].mInCollision) { mCollisionManager->AddPair(currCollObj, mFences[collisionAreaIndex][l].mFenceSimState->GetCollisionObject(), collisionAreaIndex); } } */ // all vehicles and player character have their own groundplanes already if( curr->GetAIRef() != PhysicsAIRef::redBrickVehicle && curr->GetAIRef() != PhysicsAIRef::PlayerCharacter ) { int groundPlaneIndex = mCurrentDynamics[collisionAreaIndex][k].mDynamicPhysDSG->FetchGroundPlane(); if(groundPlaneIndex != -1) // just in case, though this should never be -1 { sim::CollisionObject* gpCollObj = mGroundPlanePool->GetSimState(groundPlaneIndex)->GetCollisionObject(); gpCollObj->SetRayCastingEnabled( false ); // recall, collision is disabled on the ground plane until it is set on by the object using it mCollisionManager->AddCollisionObject( gpCollObj, collisionAreaIndex ); mCollisionManager->AddPair(currCollObj, gpCollObj, collisionAreaIndex); } } break; } } //rAssert(k < mMaxDynamics); // TODO - deal with no available slots.... } } // now look through remaining list and remove unclean // // at this stage, we can only remove the ones that are unclean and at rest. PurgeDynamics( collisionAreaIndex ); } //============================================================================= // static bool IsBreakable //============================================================================= // Description: Comment // // Parameters: ( DynaPhysDSG* pObject ) // // Return: static // //============================================================================= static bool IsBreakable( DynaPhysDSG* pObject ) { bool isBreakable; CollisionAttributes* attr = pObject->GetCollisionAttributes(); if ( pObject->GetAIRef() == PhysicsAIRef::StateProp || pObject->GetAIRef() == PhysicsAIRef::ActorStateProp ) { // *some* stateprops can break, but not ones flagged as PROP_ONE_TIME_MOVEABLE if ( pObject->GetCollisionAttributes()->GetClasstypeid() == PROP_ONETIME_MOVEABLE ) isBreakable = false; else isBreakable = true; } else if ( attr != NULL ) { if ( attr->GetClasstypeid() == PROP_BREAKABLE ) { isBreakable = true; } else { isBreakable = false; } } else { isBreakable = false; } return isBreakable; } //============================================================================= // WorldPhysicsManager::PurgeDynamics //============================================================================= // Description: Comment // // Parameters: ( int collisionAreaIndex ) // // Return: void // //============================================================================= void WorldPhysicsManager::PurgeDynamics( int collisionAreaIndex ) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); for(int i = 0; i < mMaxDynamics; i++) { // TODO ! // test for vehicles must be different; // they use they're own ground plane! if( mCurrentDynamics[collisionAreaIndex][i].mDynamicPhysDSG != 0 && mCurrentDynamics[collisionAreaIndex][i].clean == false ) { DynaPhysDSG* pObject = mCurrentDynamics[collisionAreaIndex][i].mDynamicPhysDSG; // need to keep updating when "at rest" if it's a onetime movable that has been hit // so that it can be removed when it goes out of view bool atRest = pObject->IsAtRest(); if(atRest && pObject->GetCollisionAttributes()) { atRest = atRest && !((pObject->GetCollisionAttributes()->GetClasstypeid() == PROP_ONETIME_MOVEABLE) && pObject->mIsHit); } if ( atRest || IsBreakable( pObject ) ) { mCollisionManager->RemoveCollisionObject(pObject->mpSimState()->GetCollisionObject(), collisionAreaIndex); // don't do fuck if we are a car - temp TODO!! // this test doesn't seem to work if(pObject->GetAIRef() != PhysicsAIRef::redBrickVehicle) { int groundPlaneIndex = pObject->GetGroundPlaneIndex(); if(groundPlaneIndex != -1) // should never be false... { sim::CollisionObject* gpCollObj = mGroundPlanePool->GetSimState(groundPlaneIndex)->GetCollisionObject(); mCollisionManager->RemoveCollisionObject(gpCollObj, collisionAreaIndex); pObject->FreeGroundPlane(); // this decrements the groundplaneref, but we still need to take it out of // there are no more refs } } pObject->Release( ); mCurrentDynamics[collisionAreaIndex][i].mDynamicPhysDSG = 0; mCurrentDynamics[collisionAreaIndex][i].clean = false; // this is redundant } } } } //============================================================================= // WorldPhysicsManager::UpdateSimluatingDynamicObjectGroundPlanes //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void WorldPhysicsManager::UpdateSimluatingDynamicObjectGroundPlanes() { int i; for(i = 0; i < mNumCollisionAreas; i++) { if(!mCollisionAreaAllocated[i]) { continue; } int j; for(j = 0; j < mMaxDynamics; j++) { if( mCurrentDynamics[i][j].mDynamicPhysDSG && mCurrentDynamics[i][j].mDynamicPhysDSG->GetSimState()->GetControl() == sim::simSimulationCtrl && mCurrentDynamics[i][j].mDynamicPhysDSG->GetSimState()->mAIRefIndex != PhysicsAIRef::redBrickVehicle && mCurrentDynamics[i][j].mDynamicPhysDSG->GetSimState()->mAIRefIndex != PhysicsAIRef::PlayerCharacter ) // TODO - vehicles use also? // TODO - rest test??? or is that covered under sim control? { // need to update this ground plane // TODO // is the position of the DSG object being updated correctly??????? // // no implementatino of that for dynamics yet! rmt::Vector inPosition = mCurrentDynamics[i][j].mDynamicPhysDSG->rPosition(); float inRadius = 1.0f; // ignore the tri values rmt::Vector triNormal; rmt::Vector triPosition; bool foundPlane; rmt::Vector planeNormal; rmt::Vector planePosition; GetIntersectManager()->FindIntersection(inPosition, foundPlane, planeNormal, planePosition); if(foundPlane) { mGroundPlanePool->UpdateGroundPlane(mCurrentDynamics[i][j].mDynamicPhysDSG->GetGroundPlaneIndex(), planePosition, planeNormal); } else { //rAssert(0); int stophere = 1; // hopefully not. } } } } } //============================================================================= // WorldPhysicsManager::GetNewGroundPlane //============================================================================= // Description: Comment // // Parameters: () // // Return: int // //============================================================================= int WorldPhysicsManager::GetNewGroundPlane(sim::SimState* simStateOwner) { return mGroundPlanePool->GetNewGroundPlane(simStateOwner); } //============================================================================= // WorldPhysicsManager::FreeGroundPlane //============================================================================= // Description: Comment // // Parameters: (int index) // // Return: void // //============================================================================= void WorldPhysicsManager::FreeGroundPlane(int index) { mGroundPlanePool->FreeGroundPlane(index); } //============================================================================= // WorldPhysicsManager::EnableGroundPlaneCollision //============================================================================= // Description: Comment // // Parameters: (int index) // // Return: void // //============================================================================= void WorldPhysicsManager::EnableGroundPlaneCollision(int index) { //char buffy[128]; //sprintf(buffy, "enabling ground plane index %d\n", index); //rReleaseString(buffy); mGroundPlanePool->EnableCollision(index); } //============================================================================= // WorldPhysicsManager::DisableGroundPlaneCollision //============================================================================= // Description: Comment // // Parameters: (int index) // // Return: void // //============================================================================= void WorldPhysicsManager::DisableGroundPlaneCollision(int index) { //char buffy[128]; //sprintf(buffy, "disabling ground plane index %d\n", index); //rReleaseString(buffy); mGroundPlanePool->DisableCollision(index); } //============================================================================= // WorldPhysicsManager::UpdateDynamicObjects //============================================================================= // Description: Comment // // Parameters: (float dt, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::UpdateDynamicObjects(float dt, int collisionAreaIndex) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); rAssert( mCollisionAreaAllocated[collisionAreaIndex] ); int j; for(j = 0; j < mMaxDynamics; j++) { if(mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG) { mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->RestTest(); bool atRest = mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->IsAtRest(); // need to keep updating when "at rest" if it's a onetime movable that has been hit if(atRest && mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->GetCollisionAttributes()) { atRest = atRest && !((mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->GetCollisionAttributes()->GetClasstypeid() == PROP_ONETIME_MOVEABLE) && mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->mIsHit); } // don't update vehicles or characters (they are updated elsewhere), // stuff at rest, or stuff that has already been updated. if((mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->GetSimState()->mAIRefIndex != PhysicsAIRef::redBrickVehicle) && (mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->GetSimState()->mAIRefIndex != PhysicsAIRef::PlayerCharacter ) && (!atRest) && (mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->GetLastUpdate() != updateFrame)) { // set the update tick so we wont update this again mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->SetLastUpdate(updateFrame); mCurrentDynamics[collisionAreaIndex][j].mDynamicPhysDSG->Update(dt); } } } } //============================================================================= // WorldPhysicsManager::UpdateAnimCollisions //============================================================================= // Description: Comment // // Parameters: (float dt, int collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::UpdateAnimCollisions(float dt, int collisionAreaIndex) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); rAssert(mCollisionAreaAllocated[collisionAreaIndex]); int j; for(j = 0; j < mMaxUpdateAnimCollisions; j++) { if(mCurrentUpdateAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG) { if(mCurrentUpdateAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG->GetLastUpdate() != updateFrame) { // set the update tick so we wont update this again mCurrentUpdateAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG->SetLastUpdate(updateFrame); mCurrentUpdateAnimCollisions[collisionAreaIndex][j].mAnimCollisionEntityDSG->Update(dt); } } } } //============================================================================= // WorldPhysicsManager::SubmitFencePiecesPseudoCallback //============================================================================= // Description: Comment // // Parameters: (position, radius, collisionAreaIndex) // // Return: void // //============================================================================= void WorldPhysicsManager::SubmitFencePiecesPseudoCallback(rmt::Vector& position, float radius, int collisionAreaIndex, sim::SimState* callerSimState, bool allowAutoPairing) { rAssert( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA ); ReserveArray fenceDSGList; BEGIN_PROFILE( "FindFenceElems" ); GetIntersectManager()->FindFenceElems(position, radius, fenceDSGList); END_PROFILE( "FindFenceElems" ); int numResults = fenceDSGList.mUseSize; //int numResults = 1; if(numResults > 0) { int stophere = 1; } if(numResults > mMaxFencePerArea) { numResults = mMaxFencePerArea; } // fill in debug rendering list: int i; for(i = 0; i < numResults; i++) { mFenceDSGResults[i]->mStartPoint = fenceDSGList[i]->mStartPoint; mFenceDSGResults[i]->mEndPoint = fenceDSGList[i]->mEndPoint; mFenceDSGResults[i]->mNormal = fenceDSGList[i]->mNormal; mFenceDSGResults[i]->mStartPoint.y = position.y; mFenceDSGResults[i]->mEndPoint.y = position.y; } mNumDebugFences = numResults; // reset list for(i = 0; i < mMaxFencePerArea; i++) { mFences[collisionAreaIndex][i].mClean = false; } for(i = 0; i < numResults; i++) { // i is candidate for submission // just in case, do this in function, not here //fenceDSGList[i]->mStartPoint.y = position.y; //fenceDSGList[i]->mEndPoint.y = position.y; mFences[collisionAreaIndex][i].start = fenceDSGList[i]->mStartPoint; mFences[collisionAreaIndex][i].end = fenceDSGList[i]->mEndPoint; if(UpdateFencePiece(position, mFences[collisionAreaIndex][i].mFenceSimState, fenceDSGList[i]->mStartPoint, fenceDSGList[i]->mEndPoint, fenceDSGList[i]->mNormal, callerSimState)) { // ok for this one to be in collision // if(mFences[collisionAreaIndex][i].mInCollision == false) { // we need to add this into the collision manager if(allowAutoPairing) { mFences[collisionAreaIndex][i].mFenceSimState->GetCollisionObject()->SetAutoPair(true); } else { mFences[collisionAreaIndex][i].mFenceSimState->GetCollisionObject()->SetAutoPair(false); } mCollisionManager->AddCollisionObject(mFences[collisionAreaIndex][i].mFenceSimState->GetCollisionObject(), collisionAreaIndex); mCollisionManager->AddPair(callerSimState->GetCollisionObject(), mFences[collisionAreaIndex][i].mFenceSimState->GetCollisionObject(), collisionAreaIndex); mFences[collisionAreaIndex][i].mInCollision = true; } mFences[collisionAreaIndex][i].mClean = true; } } // update list for(i = 0; i < mMaxFencePerArea; i++) { if(mFences[collisionAreaIndex][i].mInCollision == true && mFences[collisionAreaIndex][i].mClean == false) { mCollisionManager->RemoveCollisionObject(mFences[collisionAreaIndex][i].mFenceSimState->GetCollisionObject(), collisionAreaIndex); mFences[collisionAreaIndex][i].mInCollision = false; } } } //============================================================================= // WorldPhysicsManager::UpdateFencePiece //============================================================================= // Description: Comment // // Parameters: (SimState* fencePiece, rmt::Vector* end0, rmt::Vector* end1, rmt::Vector* normal) // // Return: void // //============================================================================= bool WorldPhysicsManager::UpdateFencePiece(rmt::Vector& callerPosition, sim::ManualSimState* fencePiece, rmt::Vector& end0, rmt::Vector& end1, rmt::Vector& normal, sim::SimState* callerSimState) { // on the collision volume // set position, // mAxis // mLength rmt::Vector o0, o1, o2; float l0, l1, l2; // pain in the ass - just get it to fucking work rmt::Vector localEnd0 = end0; rmt::Vector localEnd1 = end1; localEnd0.y = callerPosition.y; localEnd1.y = callerPosition.y; o1.Set(0.0f, 1.0f, 0.0f); // y is always straight up o2 = normal; // safe to assume this is normalized? o0.CrossProduct(o1, o2); //l1 = 10000.0f; // magic big ass number l1 = 10.0f; // use a smaller number for now so the debug drawn volumes are easier to see rmt::Vector segment; segment.Sub(localEnd1, localEnd0); float segmentLength = segment.Magnitude(); l0 = segmentLength * 0.5f; l2 = 10.0f; // ? whatever? TODO - is this value ok? if(callerSimState->mAIRefIndex == PhysicsAIRef::CameraSphere) { // Cary! // change this number! // this is half the length of the fence piece obbox l2 = 2.0f; //l2 = 10.0f; } rmt::Vector midpoint; midpoint.Add(localEnd0, localEnd1); midpoint.Scale(0.5f); // before doing anything else, test if we are pointed at the fucker // TODO - maybe this test should be moved up to the submit part? // maybe not rmt::Vector test; test.Sub(callerPosition, midpoint); if(test.DotProduct(normal) < 0.0f && callerSimState->mAIRefIndex != PhysicsAIRef::CameraSphere) { fencePiece->GetCollisionObject()->SetCollisionEnabled(false); return false; } rmt::Vector position = midpoint; rmt::Vector centerAdjust = o2; centerAdjust.Scale(l2); position.Sub(centerAdjust); // for convenience: sim::CollisionObject* co = fencePiece->GetCollisionObject(); sim::OBBoxVolume* obbox = (OBBoxVolume*)(co->GetCollisionVolume()); obbox->Set(position, o0, o1, o2, l0, l1, l2); co->PostManualUpdate(); //co->Relocated(); //obbox->UpdateBBox(); // only need to do this once co->SetCollisionEnabled(true); // on the Object call Relocated // //virtual void UpdateBBox() {} // make sure mUpdated is true // what about dP?? // // what about OptimizeAxis // what about SetRotation? // GetCollisionObject()->SetCollisionEnabled(true); //#ifdef RAD_DEBUG //sim::DrawCollisionObject(CollisionObject* inObject); //sim::DrawCollisionVolume(obbox); //#endif return true; } //---------------------------------------------------------------------------- // Segment intersection, stolen, as usual, from www.magic-software.com //---------------------------------------------------------------------------- // even though we're using 3d vectors (cause that's what we have) this is only a 2d intersection // in x & z static bool Find (const rmt::Vector& rkP0, const rmt::Vector& rkD0, const rmt::Vector& rkP1, const rmt::Vector& rkD1, rmt::Vector& rkDiff, float& rfD0SqrLen, int& riQuantity, float afT[2]) { // Intersection is a solution to P0+s*D0 = P1+t*D1. Rewrite as // s*D0 - t*D1 = P1 - P0, a 2x2 system of equations. If D0 = (x0,y0) // and D1 = (x1,y1) and P1 - P0 = (c0,c1), then the system is // x0*s - x1*t = c0 and y0*s - y1*t = c1. The error tests are relative // to the size of the direction vectors, |Cross(D0,D1)| >= e*|D0|*|D1| // rather than absolute tests |Cross(D0,D1)| >= e. The quantities // P1-P0, |D0|^2, and |D1|^2 are returned for use by calling functions. float fDet = rkD1.x*rkD0.z - rkD1.z*rkD0.x; rkDiff = rkP1 - rkP0; rfD0SqrLen = rkD0.MagnitudeSqr(); const float fEpsilon = 1e-06f; if ( fDet*fDet > fEpsilon*rfD0SqrLen*rkD1.MagnitudeSqr() ) { // Lines intersect in a single point. Return both s and t values for // use by calling functions. float fInvDet = 1.0f/fDet; riQuantity = 1; afT[0] = (rkD1.x*rkDiff.z - rkD1.z*rkDiff.x)*fInvDet; afT[1] = (rkD0.x*rkDiff.z - rkD0.z*rkDiff.x)*fInvDet; } else { // lines are parallel fDet = rkD0.x*rkDiff.z - rkD0.z*rkDiff.x; if ( fDet*fDet > fEpsilon*rfD0SqrLen*rkDiff.MagnitudeSqr() ) { // lines are disjoint riQuantity = 0; } else { // lines are the same riQuantity = 2; } } return riQuantity != 0; } //---------------------------------------------------------------------------- static bool FindIntersection (const rmt::Vector& origin0, const rmt::Vector& direction0, const rmt::Vector& origin1, const rmt::Vector& direction1, int& riQuantity) { float afT[2]; rmt::Vector kDiff; float fD0SqrLen; bool bIntersects = Find(origin0, direction0, origin1,direction1,kDiff,fD0SqrLen, riQuantity,afT); if ( bIntersects ) { if ( riQuantity == 1 ) { if ( afT[0] < 0.0f || afT[0] > 1.0f || afT[1] < 0.0f || afT[1] > 1.0f ) { // lines intersect, but segments do not riQuantity = 0; } } else { // segments are on the same line float fDotRS = direction0.Dot(direction1); float fDot0, fDot1; if ( fDotRS > 0.0f ) { fDot0 = kDiff.Dot(direction0); fDot1 = fDot0 + fDotRS; } else { fDot1 = kDiff.Dot(direction0); fDot0 = fDot1 + fDotRS; } // compute intersection of [t0,t1] and [0,1] if ( fDot1 < 0.0f || fDot0 > fD0SqrLen ) { riQuantity = 0; } else if ( fDot1 > 0.0f ) { if ( fDot0 < fD0SqrLen ) { float fInvLen = 1.0f/fD0SqrLen; riQuantity = 2; afT[0] = ( fDot0 < 0.0f ? 0.0f : fDot0*fInvLen ); afT[1] = ( fDot1 > fD0SqrLen ? 1.0f : fDot1*fInvLen ); } else // fT0 == 1 { riQuantity = 1; afT[0] = 1.0f; } } else // fT1 == 0 { riQuantity = 1; afT[0] = 0.0f; } } } return riQuantity != 0; } bool WorldPhysicsManager::FenceSanityCheck(unsigned collisionAreaIndex, const rmt::Vector lastFrame, const rmt::Vector thisFrame, rmt::Vector* fixPos) { rmt::Vector dir, dirTweak; dir.Sub(thisFrame, lastFrame); if(dir.MagnitudeSqr() == 0.0f) { return false; } dirTweak = dir; dirTweak.Normalize(); dirTweak.Scale(0.07f); dir += dirTweak; for(int i = 0; i < mMaxFencePerArea; i++) { if(mFences[collisionAreaIndex][i].mClean) { rmt::Vector fenceDir, fenceTweak, fenceStart; fenceDir.Sub(mFences[collisionAreaIndex][i].end, mFences[collisionAreaIndex][i].start); fenceTweak = fenceDir; fenceTweak.Normalize(); fenceTweak.Scale(0.07f); fenceDir += fenceTweak; fenceDir += fenceTweak; fenceStart = mFences[collisionAreaIndex][i].start; fenceStart -= fenceTweak; int quantity; if(FindIntersection(lastFrame, dir, fenceStart, fenceDir, quantity)) { if(quantity == 1) { *fixPos = lastFrame; fixPos->y = thisFrame.y; return true; } } } } return false; } float WorldPhysicsManager::GetLoopTime() { return mLoopTime; }