The-Simpsons-Hit-and-Run/game/code/worldsim/worldphysicsmanager.cpp

2922 lines
94 KiB
C++

//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: worldphysicsmanager.cpp
//
// Description: bleek
//
// History: May 1, 2002 - created, gmayer
//
//=============================================================================
//========================================
// System Includes
//========================================
#include <raddebug.hpp>
#include <simcommon/simstatearticulated.hpp>
#include <simcommon/simenvironment.hpp>
#include <simcollision/collisionmanager.hpp>
#include <simcommon/physicsproperties.hpp>
#include <simcollision/collisionvolume.hpp>
#include <simcollision/collisiondisplay.hpp>
#include <simcommon/simutility.hpp>
//========================================
// Project Includes
//========================================
#include <render/DSG/animcollisionentitydsg.h>
#include <worldsim/worldphysicsmanager.h>
#include <worldsim/worldcollisionsolveragent.h>
#include <worldsim/groundplanepool.h>
#include <worldsim/avatarmanager.h>
#include <worldsim/vehiclecentral.h>
#include <memory/srrmemory.h>
#include <worldsim/redbrick/vehicle.h>
#include <worldsim/redbrick/physicslocomotion.h> // just for debug prinout
#include <camera/supercammanager.h>
#include <debug/profiler.h>
#include <debug/debuginfo.h>
#include <render/Culling/ReserveArray.h>
#include <render/DSG/StaticPhysDSG.h>
#include <render/DSG/StatePropDSG.h>
#include <render/DSG/FenceEntityDSG.h>
#include <render/IntersectManager/IntersectManager.h>
#include <worldsim/character/charactermanager.h>
#include <worldsim/character/character.h>
#include <ai/actionbuttonmanager.h>
#include <constants/maxplayers.h>
#include <constants/maxnpccharacters.h>
#include <sound/soundmanager.h>
#include <mission/gameplaymanager.h>
// TODO
// can remove
// just here to hack in a light so I can see the texture damage states better
#include <render/RenderManager/RenderManager.h>
#include <render/RenderManager/RenderLayer.h>
//******************************************************************************
//
// 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<mNumCollisionAreas; index++)
{
if(mCollisionAreaAllocated[index]) // should not be trying to free up one that is not in use
{
FreeCollisionAreaIndex(index);
}
}
}
//=============================================================================
// WorldPhysicsManager::RemoveVehicleFromAnyOtherCurrentDynamicsList
//=============================================================================
// Description: Comment
//
// Parameters: (Vehicle* vehicle)
//
// Return: void
//
//=============================================================================
void WorldPhysicsManager::RemoveFromAnyOtherCurrentDynamicsListAndCollisionArea(DynaPhysDSG* obj)
{
int i;
// Vehicle* vehicle = dynamic_cast<Vehicle*>(obj);
// Character* character= dynamic_cast<Character*>(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<float>(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<StaticPhysDSG*> 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<AnimCollisionEntityDSG*> 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<AnimCollisionEntityDSG*> 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<DynaPhysDSG*> 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<FenceEntityDSG*> 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;
}