1330 lines
39 KiB
C++
1330 lines
39 KiB
C++
//=============================================================================
|
|
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
|
|
//
|
|
// File: triggervolumetracker.cpp
|
|
//
|
|
// Description: Implement TriggerVolumeTracker
|
|
//
|
|
// History: 13/05/2002 + Created -- NAME
|
|
//
|
|
//=============================================================================
|
|
|
|
//========================================
|
|
// System Includes
|
|
//========================================
|
|
// Foundation Tech
|
|
#include <raddebug.hpp>
|
|
#include <raddebugwatch.hpp>
|
|
#include <radmath/radmath.hpp>
|
|
#include <radtime.hpp>
|
|
|
|
#include <p3d/debugdraw.hpp>
|
|
|
|
//========================================
|
|
// Project Includes
|
|
//========================================
|
|
#include <meta/triggervolumetracker.h>
|
|
#include <meta/triggervolume.h>
|
|
#include <meta/triggerlocator.h>
|
|
#include <meta/locatorevents.h>
|
|
#include <meta/eventlocator.h>
|
|
#include <meta/locatortypes.h>
|
|
#include <meta/zoneeventlocator.h>
|
|
|
|
#include <main/commandlineoptions.h>
|
|
|
|
#include <memory/srrmemory.h>
|
|
|
|
#include <worldsim/avatarmanager.h>
|
|
#include <worldsim/avatar.h>
|
|
#include <worldsim/vehiclecentral.h>
|
|
#include <worldsim/redbrick/vehicle.h>
|
|
|
|
#include <mission/gameplaymanager.h>
|
|
|
|
#include <debug/profiler.h>
|
|
|
|
#include <render/intersectmanager/intersectmanager.h>
|
|
|
|
#include <camera/supercammanager.h>
|
|
#include <camera/supercamcentral.h>
|
|
#include <camera/supercam.h>
|
|
|
|
#include <simcommon/simstate.hpp>
|
|
#include <simcommon/simstatearticulated.hpp>
|
|
#include <simcommon/simulatedobject.hpp>
|
|
#include <simcommon/simenvironment.hpp>
|
|
#include <simcollision/collisionobject.hpp>
|
|
#include <simcollision/collisionvolume.hpp>
|
|
#include <simcollision/collisionmanager.hpp>
|
|
|
|
|
|
LocatorEvent::Event ALLOWED_AI_EVENTS[] =
|
|
{
|
|
LocatorEvent::DEATH,
|
|
LocatorEvent::PARKED_BIRDS,
|
|
LocatorEvent::WHACKY_GRAVITY,
|
|
LocatorEvent::GOO_DAMAGE
|
|
};
|
|
|
|
unsigned int NUM_ALLOWED_AI_EVENTS = sizeof( ALLOWED_AI_EVENTS ) / sizeof( ALLOWED_AI_EVENTS[0] );
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Global Data, Local Data, Local Classes
|
|
//
|
|
//******************************************************************************
|
|
|
|
// Static pointer to instance of singleton.
|
|
TriggerVolumeTracker* TriggerVolumeTracker::spInstance = NULL;
|
|
|
|
rmt::Vector TriggerVolumeTracker::sP1;
|
|
rmt::Vector TriggerVolumeTracker::sP2;
|
|
rmt::Vector TriggerVolumeTracker::sP3;
|
|
rmt::Vector TriggerVolumeTracker::sP4;
|
|
|
|
sim::CollisionVolumeTypeEnum TriggerVolumeTracker::sColType;
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Public Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
void TriggerVolumeTracker::CreateInstance()
|
|
{
|
|
MEMTRACK_PUSH_GROUP( "TriggerVolumeTracker" );
|
|
rAssert( spInstance == NULL );
|
|
spInstance = new(GMA_PERSISTENT) TriggerVolumeTracker();
|
|
rAssert( spInstance );
|
|
MEMTRACK_POP_GROUP( "TriggerVolumeTracker" );
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::GetInstance
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: TriggerVolumeTracker
|
|
//
|
|
//=============================================================================
|
|
TriggerVolumeTracker* TriggerVolumeTracker::GetInstance()
|
|
{
|
|
//rAssert( spInstance );
|
|
return spInstance;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::DestroyInstance
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::DestroyInstance()
|
|
{
|
|
if( spInstance != NULL )
|
|
{
|
|
delete( GMA_PERSISTENT, spInstance );
|
|
spInstance = NULL;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// TriggerVolumeTracker::TriggerVolumeTracker
|
|
//==============================================================================
|
|
// Description: Constructor.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: N/A.
|
|
//
|
|
//==============================================================================
|
|
TriggerVolumeTracker::TriggerVolumeTracker() :
|
|
mpTriggerSphere( NULL ),
|
|
mNumRegisteredAI( 0 ),
|
|
mIgnoreTriggers ( false )
|
|
#ifndef RAD_RELEASE
|
|
,
|
|
mDisplayAmbients( false ),
|
|
mDisplayActive( true ),
|
|
mDisplayInactive( false ),
|
|
mDisplayAll( false )
|
|
#endif
|
|
{
|
|
int i;
|
|
for( i = 0; i < MAX_PLAYERS; i++ )
|
|
{
|
|
mActiveCount[ i ] = 0;
|
|
}
|
|
|
|
for ( i = 0; i < MAX_AI; ++i )
|
|
{
|
|
mAICount[ i ] = 0;
|
|
}
|
|
|
|
mTriggerCount = 0;
|
|
|
|
#ifndef RAD_RELEASE
|
|
radDbgWatchAddBoolean( &mDisplayActive, "Display Active Vols" , "Trigger Volume Tracker" );
|
|
radDbgWatchAddBoolean( &mDisplayInactive, "Display Inactive Vols" , "Trigger Volume Tracker" );
|
|
radDbgWatchAddBoolean( &mDisplayAll, "Display ALL" , "Trigger Volume Tracker" );
|
|
|
|
for ( i = 0; i < LocatorType::NUM_TYPES; ++i )
|
|
{
|
|
char name[256];
|
|
sprintf( name, "Display %s", LocatorType::Name[i] );
|
|
radDbgWatchAddBoolean( &mDisplayEnable[i], name , "Trigger Volume Tracker" );
|
|
mDisplayEnable[i] = false;
|
|
}
|
|
|
|
radDbgWatchAddBoolean( &mDisplayAmbients, "Display Ambients", "Trigger Volume Tracker" );
|
|
|
|
material = NULL;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifndef RAD_RELEASE
|
|
pddiShader* TriggerVolumeTracker::GetMaterial(void)
|
|
{
|
|
if(!material)
|
|
{
|
|
HeapMgr()->PushHeap(GMA_PERSISTENT);
|
|
material = p3d::device->NewShader( "simple" );
|
|
material->AddRef();
|
|
material->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD);
|
|
material->SetColour( PDDI_SP_AMBIENT, pddiColour( 128, 128, 128, 64 ));
|
|
material->SetColour( PDDI_SP_DIFFUSE, pddiColour( 128, 128, 128, 64 ));
|
|
HeapMgr()->PopHeap(GMA_PERSISTENT);
|
|
}
|
|
|
|
return material;
|
|
}
|
|
#endif
|
|
|
|
//==============================================================================
|
|
// TriggerVolumeTracker::~TriggerVolumeTracker
|
|
//==============================================================================
|
|
// Description: Destructor.
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: N/A.
|
|
//
|
|
//==============================================================================
|
|
TriggerVolumeTracker::~TriggerVolumeTracker()
|
|
{
|
|
Cleanup();
|
|
|
|
#ifndef RAD_RELEASE
|
|
radDbgWatchDelete( &mDisplayActive );
|
|
radDbgWatchDelete( &mDisplayInactive );
|
|
radDbgWatchDelete( &mDisplayAll );
|
|
|
|
int i;
|
|
for ( i = 0; i < LocatorType::NUM_TYPES; ++i )
|
|
{
|
|
radDbgWatchDelete( &mDisplayEnable[i] );
|
|
}
|
|
|
|
radDbgWatchDelete( &mDisplayAmbients );
|
|
|
|
if ( material )
|
|
{
|
|
material->Release();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::Cleanup
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::Cleanup()
|
|
{
|
|
unsigned int i;
|
|
int j;
|
|
for( j = 0; j < MAX_PLAYERS; j++ )
|
|
{
|
|
for( i = 0; i < mActiveCount[ j ]; i++ )
|
|
{
|
|
mActiveVolumes[ j ][ i ]->Release();
|
|
mActiveVolumes[ j ][ i ] = NULL;
|
|
}
|
|
|
|
mActiveCount[ j ] = 0;
|
|
}
|
|
|
|
for ( j = 0; j < MAX_AI; ++j )
|
|
{
|
|
for ( i = 0; i < mAICount[ j ]; ++i )
|
|
{
|
|
mActiveAIVolumes[ j ][ i ]->Release();
|
|
mActiveAIVolumes[ j ][ i ] = NULL;
|
|
}
|
|
|
|
mAICount[ j ] = 0;
|
|
}
|
|
|
|
if ( mNumRegisteredAI > 0 )
|
|
{
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
mRegisteredVehicles[ i ].mVehicle->Release();
|
|
mRegisteredVehicles[ i ].mVehicle = NULL;
|
|
}
|
|
}
|
|
|
|
mNumRegisteredAI = 0;
|
|
|
|
for( i = 0; i < mTriggerCount; i++ )
|
|
{
|
|
mTriggerVolumes[ i ]->Release();
|
|
mTriggerVolumes[ i ] = NULL;
|
|
}
|
|
|
|
mTriggerCount = 0;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::Update
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int elapsedTime )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::Update( int elapsedTime )
|
|
{
|
|
if ( mIgnoreTriggers )
|
|
{
|
|
//Do nothing
|
|
return;
|
|
}
|
|
|
|
BEGIN_PROFILE("Trigger Tracker");
|
|
|
|
rmt::Vector center;
|
|
const float radius = 1.0f;
|
|
|
|
unsigned int iNumPlayers = GetGameplayManager()->GetNumPlayers();
|
|
|
|
unsigned int i;
|
|
for( i = 0; i < iNumPlayers; i++ )
|
|
{
|
|
// get the player's location and bounding sphere radius
|
|
GetAvatarManager()->GetAvatarForPlayer( i )->GetPosition( center );
|
|
|
|
CheckForActiveVolumes( i, center, radius );
|
|
}
|
|
|
|
VehicleCentral* vc = GetVehicleCentral();
|
|
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
rmt::Vector pos;
|
|
mRegisteredVehicles[ i ].mVehicle->GetPosition( &pos );
|
|
|
|
int id = vc->GetVehicleId( mRegisteredVehicles[ i ].mVehicle );
|
|
|
|
CheckForActiveVolumes( id + MAX_PLAYERS, pos, radius );
|
|
}
|
|
|
|
END_PROFILE("Trigger Tracker");
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::AddTrigger
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( TriggerVolume* triggerVolume )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::AddTrigger( TriggerVolume* triggerVolume )
|
|
{
|
|
rAssert( mTriggerCount < MAX_VOLUMES );
|
|
unsigned int index;
|
|
for( index = 0; index < mTriggerCount; index++ )
|
|
{
|
|
if( mTriggerVolumes[ index ] == triggerVolume )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
mTriggerVolumes[ mTriggerCount ] = triggerVolume;
|
|
triggerVolume->AddRef();
|
|
|
|
mTriggerCount++;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::RemoveTrigger
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( TriggerVolume* triggerVolume )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::RemoveTrigger( TriggerVolume* triggerVolume )
|
|
{
|
|
unsigned int index;
|
|
for( index = 0; index < mTriggerCount; index++ )
|
|
{
|
|
if( mTriggerVolumes[ index ] == triggerVolume )
|
|
{
|
|
//Shift the last trigger into the new empty position.
|
|
mTriggerVolumes[ index ] = mTriggerVolumes[ mTriggerCount-1 ];
|
|
triggerVolume->Release();
|
|
|
|
mTriggerCount--;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
for( int player = 0; player < GetGameplayManager()->GetNumPlayers(); player++ )
|
|
{
|
|
for( index = 0; index < mActiveCount[ player ]; index++ )
|
|
{
|
|
if( mActiveVolumes[ player ][ index ] == triggerVolume )
|
|
{
|
|
RemoveActive( player, index );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( unsigned int ai = 0; ai < mNumRegisteredAI; ++ai )
|
|
{
|
|
for ( index = 0; index < mAICount[ ai ]; ++index )
|
|
{
|
|
if ( mActiveAIVolumes[ ai ][ index ] == triggerVolume )
|
|
{
|
|
RemoveAIActive( ai, index );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::UnregisterFromInventory
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( tInventory* inv )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::UnregisterFromInventory( tInventory* inv )
|
|
{
|
|
//BEGIN_PROFILE( "Trigger Tracker Unregister Inventory ");
|
|
|
|
rAssert( inv );
|
|
|
|
if ( inv )
|
|
{
|
|
HeapMgr()->PushHeap( GMA_TEMP );
|
|
tInventory::Iterator<TriggerVolume> it;
|
|
HeapMgr()->PopHeap( GMA_TEMP );
|
|
|
|
TriggerVolume* tv = it.First();
|
|
|
|
while ( tv != NULL )
|
|
{
|
|
RemoveTrigger( tv );
|
|
|
|
tv = it.Next();
|
|
}
|
|
}
|
|
//END_PROFILE( "Trigger Tracker Unregister Inventory ");
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::HandleEvent
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( EventEnum id, void* pEventData )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::HandleEvent( EventEnum id, void* pEventData )
|
|
{
|
|
switch( id )
|
|
{
|
|
case EVENT_LOCATOR:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// implement all events this class is registered for!
|
|
rAssert( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::Render
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::Render()
|
|
{
|
|
#ifndef RAD_RELEASE
|
|
const Locator* locator;
|
|
unsigned int i;
|
|
|
|
/*
|
|
Avatar* playerAvatar = GetAvatarManager()->GetAvatarForPlayer( 0 );
|
|
rAssert( playerAvatar );
|
|
|
|
if ( playerAvatar->IsInCar() )
|
|
{
|
|
//Test the car like it was the "Green Lantern" | 0 |. Two lines and
|
|
//a sphere.
|
|
//Get the BBOX of the car
|
|
|
|
Vehicle* vehicle = playerAvatar->GetVehicle();
|
|
|
|
sim::CollisionVolume* vecol = vehicle->GetSimState()->GetCollisionObject()->GetCollisionVolume()->GetSubCollisionVolume( 0 );
|
|
rAssert( vecol->Type() == sim::OBBoxVolumeType );
|
|
|
|
sim::OBBoxVolume* obBox = static_cast<sim::OBBoxVolume*>( vecol );
|
|
|
|
rmt::Vector minCorner, maxCorner;
|
|
|
|
minCorner.x = - obBox->mLength[0];
|
|
minCorner.y = - obBox->mLength[1];
|
|
minCorner.z = - obBox->mLength[2];
|
|
|
|
maxCorner.x = obBox->mLength[0];
|
|
maxCorner.y = obBox->mLength[1];
|
|
maxCorner.z = obBox->mLength[2];
|
|
|
|
p3d::stack->Push();
|
|
|
|
rmt::Matrix positionMatrix;
|
|
positionMatrix.Identity();
|
|
positionMatrix.Row(0) = obBox->mAxis[0];
|
|
positionMatrix.Row(1) = obBox->mAxis[1];
|
|
positionMatrix.Row(2) = obBox->mAxis[2];
|
|
positionMatrix.Row(3) = obBox->mPosition;
|
|
|
|
|
|
p3d::stack->Multiply(positionMatrix);
|
|
|
|
|
|
tShader* shader = new tShader("simple");
|
|
shader->AddRef();
|
|
|
|
P3DDrawOrientedBox( minCorner, maxCorner, *shader );
|
|
|
|
shader->Release();
|
|
|
|
p3d::stack->Pop();
|
|
}
|
|
*/
|
|
for( i = 0; i < mTriggerCount; i++ )
|
|
{
|
|
if ( mDisplayAll )
|
|
{
|
|
mTriggerVolumes[ i ]->Render();
|
|
continue;
|
|
}
|
|
|
|
locator = mTriggerVolumes[ i ]->GetLocator();
|
|
|
|
if ( CommandLineOptions::Get( CLO_SHOW_DYNA_ZONES ) && locator->GetDataType() == LocatorType::DYNAMIC_ZONE )
|
|
{
|
|
mTriggerVolumes[ i ]->Render();
|
|
}
|
|
else if ( !locator )
|
|
{
|
|
}
|
|
else if ( mDisplayActive && locator->GetFlag( Locator::ACTIVE ) )
|
|
{
|
|
if ( mDisplayEnable[ locator->GetDataType() ] )
|
|
{
|
|
mTriggerVolumes[ i ]->Render();
|
|
}
|
|
else if ( locator->GetDataType() == LocatorType::EVENT )
|
|
{
|
|
//We want to look at the ambient events.
|
|
EventLocator* evtLoc = (EventLocator*)( locator );
|
|
LocatorEvent::Event event = evtLoc->GetEventType();
|
|
if ( mDisplayAmbients &&
|
|
(( event >= LocatorEvent::AMBIENT_SOUND_CITY &&
|
|
event <= LocatorEvent::AMBIENT_SOUND_MANSION_INTERIOR ) ||
|
|
( event >= LocatorEvent::AMBIENT_SOUND_COUNTRY_NIGHT &&
|
|
event <= LocatorEvent::AMBIENT_SOUND_PLACEHOLDER9 ) ||
|
|
( event >= LocatorEvent::AMBIENT_SOUND_SEASIDE_NIGHT &&
|
|
event <= LocatorEvent::AMBIENT_SOUND_PLACEHOLDER16 ))
|
|
)
|
|
{
|
|
mTriggerVolumes[ i ]->Render();
|
|
}
|
|
}
|
|
}
|
|
else if ( mDisplayInactive && !locator->GetFlag( Locator::ACTIVE ) )
|
|
{
|
|
if ( mDisplayEnable[ locator->GetDataType() ] )
|
|
{
|
|
mTriggerVolumes[ i ]->Render();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
rmt::Vector center;
|
|
GetAvatarManager()->GetAvatarForPlayer( 0 )->GetPosition( center );
|
|
|
|
IntersectManager* im = IntersectManager::GetInstance();
|
|
rAssert( im );
|
|
|
|
ReserveArray<TriggerVolume*> volDSGList;
|
|
|
|
//float radius = GetSuperCamManager()->GetSCC( 0 )->GetActiveSuperCam()->GetFarPlane();
|
|
float radius = 180.0f;
|
|
im->FindTrigVolElems( center, radius, volDSGList );
|
|
|
|
unsigned int time = radTimeGetMilliseconds();
|
|
|
|
//Test all the triggers around the car
|
|
for ( i = 0; i < static_cast<unsigned int>(volDSGList.mUseSize); ++i )
|
|
{
|
|
TriggerVolume* vol = volDSGList[ i ];
|
|
if ( mDisplayAll )
|
|
{
|
|
vol->Render();
|
|
continue;
|
|
}
|
|
|
|
locator = vol->GetLocator();
|
|
|
|
if ( mDisplayActive && locator->GetFlag( Locator::ACTIVE ) )
|
|
{
|
|
if ( mDisplayEnable[ locator->GetDataType() ] )
|
|
{
|
|
vol->Render();
|
|
}
|
|
}
|
|
else if ( mDisplayInactive && !locator->GetFlag( Locator::ACTIVE ) )
|
|
{
|
|
if ( mDisplayEnable[ locator->GetDataType() ] )
|
|
{
|
|
vol->Render();
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
#endif
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::GetTriggerByName
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( const char* name )
|
|
//
|
|
// Return: TriggerVolume
|
|
//
|
|
//=============================================================================
|
|
TriggerVolume* TriggerVolumeTracker::GetTriggerByName( const char* name )
|
|
{
|
|
unsigned int i;
|
|
for( i = 0; i < mTriggerCount; i++ )
|
|
{
|
|
if( strcmp( name, mTriggerVolumes[ i ]->GetName() ) == 0 )
|
|
{
|
|
return( mTriggerVolumes[ i ] );
|
|
}
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::RegisterAI
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( Vehicle* ai, int locatorTypes )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::RegisterAI( Vehicle* ai, int locatorTypes )
|
|
{
|
|
rAssert( mNumRegisteredAI < MAX_AI );
|
|
|
|
#ifdef RAD_DEBUG
|
|
unsigned int i;
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
rAssert( mRegisteredVehicles[ i ].mVehicle != ai );
|
|
}
|
|
#endif
|
|
|
|
if ( mNumRegisteredAI < MAX_AI )
|
|
{
|
|
tRefCounted::Assign( mRegisteredVehicles[ mNumRegisteredAI ].mVehicle, ai );
|
|
mRegisteredVehicles[ mNumRegisteredAI ].mTriggerTypes = locatorTypes;
|
|
}
|
|
|
|
mNumRegisteredAI++;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::UnregisterAI
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( Vehicle* ai )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::UnregisterAI( Vehicle* ai )
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
if ( mRegisteredVehicles[ i ].mVehicle == ai )
|
|
{
|
|
mRegisteredVehicles[ i ].mVehicle->Release();
|
|
mRegisteredVehicles[ i ].mVehicle = NULL;
|
|
|
|
if ( mNumRegisteredAI > 1 )
|
|
{
|
|
mRegisteredVehicles[ i ] = mRegisteredVehicles[ mNumRegisteredAI - 1 ];
|
|
mRegisteredVehicles[ mNumRegisteredAI - 1 ].mVehicle = NULL;
|
|
}
|
|
|
|
mNumRegisteredAI -= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::GetAI
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int id )
|
|
//
|
|
// Return: Vehicle
|
|
//
|
|
//=============================================================================
|
|
Vehicle* TriggerVolumeTracker::GetAI( int id )
|
|
{
|
|
rAssert( id - MAX_PLAYERS < static_cast<int>(mNumRegisteredAI) );
|
|
|
|
return mRegisteredVehicles[ id - MAX_PLAYERS ].mVehicle;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::RegisterLocatorTypeForAI
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( LocatorType::Type type, Vehicle* ai )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::RegisterLocatorTypeForAI( LocatorType::Type type, Vehicle* ai )
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
if ( mRegisteredVehicles[ i ].mVehicle == ai )
|
|
{
|
|
mRegisteredVehicles[ i ].mTriggerTypes |= ( 1 << type );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::UnregisterLocatorTypeForAI
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( LocatorType::Type type, Vehicle* ai )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::UnregisterLocatorTypeForAI( LocatorType::Type type, Vehicle* ai )
|
|
{
|
|
unsigned int i;
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
if ( mRegisteredVehicles[ i ].mVehicle == ai )
|
|
{
|
|
mRegisteredVehicles[ i ].mTriggerTypes &= ~( 1 << type );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::ResetDynaloadZones
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ()
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::ResetDynaloadZones()
|
|
{
|
|
for( int player = 0; player < GetGameplayManager()->GetNumPlayers(); player++ )
|
|
{
|
|
for( int index = 0; index < static_cast<int>( mActiveCount[ player ] ); index++ )
|
|
{
|
|
Locator* loc = mActiveVolumes[ player ][ index ]->GetLocator();
|
|
if ( !loc )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( loc->GetDataType() == LocatorType::DYNAMIC_ZONE )
|
|
{
|
|
RemoveActive( player, index );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//========================================================================
|
|
// triggervolumetracker::
|
|
//========================================================================
|
|
//
|
|
// Description:
|
|
//
|
|
// Parameters: None.
|
|
//
|
|
// Return: None.
|
|
//
|
|
// Constraints: None.
|
|
//
|
|
//========================================================================
|
|
void TriggerVolumeTracker::ActivateNearestInteriorLoadZone(int iPlayerID, rmt::Vector& irPosnRef, float iMaxDistance)
|
|
{
|
|
ZoneEventLocator* pNearestZEL = NULL;
|
|
float nearestLocatorDistSqr = iMaxDistance*iMaxDistance;
|
|
|
|
Locator* loc = NULL;
|
|
rmt::Sphere sphere;
|
|
|
|
int i;
|
|
|
|
for ( i = 0; i < static_cast<int>( mTriggerCount ); ++i )
|
|
{
|
|
loc = mTriggerVolumes[i]->GetLocator();
|
|
if(loc == NULL) continue;
|
|
|
|
if( loc->GetDataType() == LocatorType::DYNAMIC_ZONE )
|
|
{
|
|
ZoneEventLocator* pZEL = (ZoneEventLocator*)(loc);
|
|
if(pZEL->IsInteriorLoad())
|
|
{
|
|
mTriggerVolumes[i]->GetBoundingSphere(&sphere);
|
|
|
|
rmt::Vector dist;
|
|
dist.Sub(sphere.centre, irPosnRef);
|
|
float curDistSqr = dist.MagnitudeSqr();
|
|
|
|
if( (curDistSqr < nearestLocatorDistSqr)
|
|
&& (curDistSqr < ((iMaxDistance + sphere.radius) * (iMaxDistance + sphere.radius))))
|
|
{
|
|
pNearestZEL = pZEL;
|
|
nearestLocatorDistSqr = curDistSqr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pNearestZEL!=NULL)
|
|
{
|
|
pNearestZEL->Trigger(iPlayerID,true);
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
//
|
|
// Private Member Functions
|
|
//
|
|
//******************************************************************************
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::AddActive
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int playerID, TriggerVolume* triggerVolume )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::AddActive( int playerID, TriggerVolume* triggerVolume )
|
|
{
|
|
rAssert( triggerVolume != NULL );
|
|
|
|
if ( triggerVolume == NULL || !triggerVolume->TriggerAllowed( playerID ) )
|
|
return;
|
|
|
|
rAssert( mActiveCount[ playerID ] < MAX_ACTIVE );
|
|
|
|
mActiveVolumes[ playerID ][ mActiveCount[ playerID ] ] = triggerVolume;
|
|
mActiveCount[ playerID ]++;
|
|
|
|
triggerVolume->AddRef();
|
|
|
|
TriggerLocator* trigLoc = triggerVolume->GetLocator();
|
|
if ( trigLoc && trigLoc->IsPlayerTracked( playerID ) == 0 ) //returns number tracked.
|
|
{
|
|
triggerVolume->Trigger( playerID, true );
|
|
}
|
|
|
|
triggerVolume->SetTrackingPlayer( playerID, true );
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::CheckForActiveVolumes
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int playerID, rmt::Vector& center, float radius )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::CheckForActiveVolumes( int playerID, rmt::Vector& center, float radius )
|
|
{
|
|
unsigned int time = radTimeGetMilliseconds();
|
|
unsigned int i;
|
|
|
|
//BEGIN_PROFILE( "CheckForActiveVolumes" );
|
|
// IntersectManager* im = IntersectManager::GetInstance();
|
|
// rAssert( im );
|
|
//
|
|
// ReserveArray<TriggerVolume*> volDSGList;
|
|
//
|
|
//BEGIN_PROFILE( "Query Intersect Manager" );
|
|
// im->FindTrigVolElems( center, radius, volDSGList );
|
|
//END_PROFILE( "Query Intersect Manager" );
|
|
|
|
//BEGIN_PROFILE( "Car Triggers" );
|
|
//Test all the triggers around the car
|
|
// for ( i = 0; i < static_cast<unsigned int>(volDSGList.mUseSize); ++i )
|
|
// {
|
|
// TriggerVolume* vol = volDSGList[ i ];
|
|
//
|
|
// TestVolume( vol, center, radius, playerID, time );
|
|
// }
|
|
//END_PROFILE( "Car Triggers" );
|
|
|
|
int localID = playerID;
|
|
if ( playerID >= MAX_PLAYERS )
|
|
{
|
|
//localize the id
|
|
VehicleCentral* vc = GetVehicleCentral();
|
|
|
|
for ( i = 0; i < mNumRegisteredAI; ++i )
|
|
{
|
|
if ( mRegisteredVehicles[ i ].mVehicle == vc->GetVehicle( playerID - MAX_PLAYERS ) )
|
|
{
|
|
localID = i + MAX_PLAYERS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
rAssert( localID != -1 );
|
|
}
|
|
else
|
|
{
|
|
//This is a player. Store their points for testing.
|
|
//Test the car like it was the "Green Lantern" | 0 |. Two lines and
|
|
//a sphere.
|
|
//Get the BBOX of the car
|
|
|
|
Avatar* playerAvatar = GetAvatarManager()->GetAvatarForPlayer( playerID );
|
|
Vehicle* vehicle = playerAvatar->GetVehicle();
|
|
|
|
if ( vehicle )
|
|
{
|
|
/*
|
|
rmt::Vector box = vehicle->GetExtents();
|
|
rmt::Matrix carToWorld = vehicle->GetTransform();
|
|
|
|
sP1.x = -box.x;
|
|
sP1.y = -box.y;
|
|
sP1.z = -box.z;
|
|
sP1.Transform( carToWorld );
|
|
|
|
sP2.x = +box.x;
|
|
sP2.y = -box.y;
|
|
sP2.z = -box.z;
|
|
sP2.Transform( carToWorld );
|
|
|
|
sP3.x = +box.x;
|
|
sP3.y = +box.y;
|
|
sP3.z = +box.z;
|
|
sP3.Transform( carToWorld );
|
|
|
|
sP4.x = -box.x;
|
|
sP4.y = +box.y;
|
|
sP4.z = +box.z;
|
|
sP4.Transform( carToWorld );
|
|
*/
|
|
|
|
sim::CollisionVolume* vecol = vehicle->GetSimState()->GetCollisionObject()->GetCollisionVolume()->GetSubCollisionVolume( 0 );
|
|
sColType = vecol->Type();
|
|
|
|
if( sColType == sim::OBBoxVolumeType )
|
|
{
|
|
sim::OBBoxVolume* obBox = static_cast<sim::OBBoxVolume*>( vecol );
|
|
|
|
sP1.x = - obBox->mLength[0];
|
|
sP1.y = - obBox->mLength[1];
|
|
sP1.z = - obBox->mLength[2];
|
|
|
|
sP2.x = obBox->mLength[0];
|
|
sP2.y = - obBox->mLength[1];
|
|
sP2.z = - obBox->mLength[2];
|
|
|
|
sP3.x = obBox->mLength[0];
|
|
sP3.y = obBox->mLength[1];
|
|
sP3.z = obBox->mLength[2];
|
|
|
|
sP4.x = - obBox->mLength[0];
|
|
sP4.y = obBox->mLength[1];
|
|
sP4.z = obBox->mLength[2];
|
|
|
|
rmt::Matrix positionMatrix;
|
|
positionMatrix.Identity();
|
|
positionMatrix.Row(0) = obBox->mAxis[0];
|
|
positionMatrix.Row(1) = obBox->mAxis[1];
|
|
positionMatrix.Row(2) = obBox->mAxis[2];
|
|
positionMatrix.Row(3) = obBox->mPosition;
|
|
|
|
sP1.Transform( positionMatrix );
|
|
sP2.Transform( positionMatrix );
|
|
sP3.Transform( positionMatrix );
|
|
sP4.Transform( positionMatrix );
|
|
|
|
radius = rmt::Sqrt(obBox->mLength[0] + obBox->mLength[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//BEGIN_PROFILE( "Added Triggers" );
|
|
//Test all the triggers added to the trigger tracker
|
|
for ( i = 0; i < mTriggerCount; ++i )
|
|
{
|
|
rmt::Sphere sphere;
|
|
mTriggerVolumes[ i ]->GetBoundingSphere(&sphere);
|
|
|
|
rmt::Vector dist;
|
|
dist.Sub(sphere.centre, center);
|
|
|
|
if(dist.MagnitudeSqr() < ((radius + sphere.radius) * (radius + sphere.radius)))
|
|
{
|
|
TestVolume( mTriggerVolumes[ i ], center, radius, localID, time );
|
|
}
|
|
}
|
|
//END_PROFILE( "Added Triggers" );
|
|
|
|
if ( playerID < MAX_PLAYERS )
|
|
{
|
|
//BEGIN_PROFILE( "Active Triggers" );
|
|
//Test for triggers that we've left.
|
|
for( i = 0; i < mActiveCount[ playerID ]; ++i )
|
|
{
|
|
// Added a test for the active trigger volume, because it would
|
|
// seem that if a locator were not active, you wouldn't want
|
|
// the TV in the active list.
|
|
//
|
|
// TBJ [8/23/2002]
|
|
//
|
|
if( (mActiveVolumes[ playerID ][ i ]->GetLocator() && !mActiveVolumes[ playerID ][ i ]->GetLocator()->GetFlag( Locator::ACTIVE )) ||
|
|
mActiveVolumes[ playerID ][ i ]->GetFrameUsed() != time )
|
|
{
|
|
RemoveActive( playerID, i );
|
|
}
|
|
}
|
|
//END_PROFILE( "Active Triggers" );
|
|
}
|
|
else
|
|
{
|
|
localID -= MAX_PLAYERS;
|
|
|
|
for ( i = 0; i < mAICount[ localID ]; ++i )
|
|
{
|
|
if ( !mActiveAIVolumes[ localID ][ i ]->GetLocator()->GetFlag( Locator::ACTIVE ) ||
|
|
mActiveAIVolumes[ localID ][ i ]->GetFrameUsed() != time )
|
|
{
|
|
RemoveAIActive( localID, i );
|
|
}
|
|
}
|
|
}
|
|
|
|
//END_PROFILE( "CheckForActiveVolumes" );
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::RemoveActive
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int playerID, int index )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::RemoveActive( int playerID, int index )
|
|
{
|
|
TriggerVolume* vol = mActiveVolumes[ playerID ][ index ];
|
|
|
|
TriggerLocator* trigLoc = vol->GetLocator();
|
|
if ( trigLoc && trigLoc->IsPlayerTracked( playerID ) <= 1 ) //Some locators are screwy so they never track trigger voluemes. Gags, mostly
|
|
{
|
|
vol->Trigger( playerID, false );
|
|
}
|
|
|
|
vol->SetTrackingPlayer( playerID, false );
|
|
vol->Release();
|
|
|
|
if ( mActiveCount[ playerID ] > 0 )
|
|
{
|
|
mActiveVolumes[ playerID ][ index ] = mActiveVolumes[ playerID ][ mActiveCount[ playerID ] - 1 ];
|
|
mActiveVolumes[ playerID ][ mActiveCount[ playerID ] - 1 ] = NULL;
|
|
}
|
|
|
|
mActiveCount[ playerID ]--;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::AddAIActive
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int playerID, TriggerVolume* triggerVolume )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::AddAIActive( int playerID, TriggerVolume* triggerVolume )
|
|
{
|
|
rAssert( mAICount[ playerID ] < MAX_AI_VOLUMES );
|
|
|
|
if ( !triggerVolume->TriggerAllowed( playerID ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mActiveAIVolumes[ playerID ][ mAICount[ playerID ] ] = triggerVolume;
|
|
triggerVolume->AddRef();
|
|
|
|
TriggerLocator* trigLoc = triggerVolume->GetLocator();
|
|
if ( trigLoc && trigLoc->IsPlayerTracked( playerID + MAX_PLAYERS ) == 0 )
|
|
{
|
|
triggerVolume->Trigger( playerID + MAX_PLAYERS, true ); //And the hacks go on
|
|
}
|
|
|
|
triggerVolume->SetTrackingPlayer( playerID + MAX_PLAYERS, true );
|
|
|
|
mAICount[ playerID ] += 1;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::RemoveAIActive
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( int playerID, int index )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::RemoveAIActive( int playerID, int index )
|
|
{
|
|
TriggerVolume* vol = mActiveAIVolumes[ playerID ][ index ];
|
|
|
|
TriggerLocator* trigLoc = vol->GetLocator();
|
|
if ( trigLoc && trigLoc->IsPlayerTracked( playerID + MAX_PLAYERS ) == 1 )
|
|
{
|
|
vol->Trigger( playerID + MAX_PLAYERS, false );
|
|
}
|
|
|
|
vol->SetTrackingPlayer( playerID + MAX_PLAYERS, false ); //This is a hack.
|
|
vol->Release();
|
|
|
|
if ( mAICount[ playerID ] > 0 )
|
|
{
|
|
mActiveAIVolumes[ playerID ][ index ] = mActiveAIVolumes[ playerID ][ mAICount[ playerID ] - 1 ];
|
|
mActiveAIVolumes[ playerID ][ mAICount[ playerID ] - 1 ] = NULL;
|
|
}
|
|
|
|
mAICount[ playerID ] -= 1;
|
|
}
|
|
|
|
//=============================================================================
|
|
// TriggerVolumeTracker::TestVolume
|
|
//=============================================================================
|
|
// Description: Comment
|
|
//
|
|
// Parameters: ( TriggerVolume* vol, rmt::Vector& center, float radius, int playerID, unsigned int time )
|
|
//
|
|
// Return: void
|
|
//
|
|
//=============================================================================
|
|
void TriggerVolumeTracker::TestVolume( TriggerVolume* vol,
|
|
rmt::Vector& center,
|
|
float radius,
|
|
int playerID,
|
|
unsigned int time )
|
|
{
|
|
rAssert( vol );
|
|
|
|
// This is added because the AmbientDialogueTriggers do not have a locator associated with them
|
|
// with them.
|
|
if ( vol->GetLocator() != NULL )
|
|
{
|
|
if ( playerID >= MAX_PLAYERS &&
|
|
( ((1 << vol->GetLocator()->GetDataType()) & mRegisteredVehicles[ playerID - MAX_PLAYERS ].mTriggerTypes) == 0 ) )
|
|
{
|
|
return;
|
|
}
|
|
else if ( playerID >= MAX_PLAYERS )
|
|
{
|
|
//Test if this is a legal event.
|
|
if ( vol->GetLocator()->GetDataType() == LocatorType::EVENT )
|
|
{
|
|
EventLocator* evtLoc = static_cast<EventLocator*>(vol->GetLocator());
|
|
unsigned int i;
|
|
for ( i = 0; i < NUM_ALLOWED_AI_EVENTS; ++i )
|
|
{
|
|
if ( evtLoc->GetEventType() == ALLOWED_AI_EVENTS[ i ] )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i == NUM_ALLOWED_AI_EVENTS )
|
|
{
|
|
//Not allowed to trigger this.
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool collision = false;
|
|
|
|
Locator* loc = vol->GetLocator();
|
|
|
|
if ( playerID < MAX_PLAYERS &&
|
|
GetAvatarManager()->GetAvatarForPlayer( playerID )->IsInCar() &&
|
|
( loc && loc->GetDataType() != LocatorType::OCCLUSION ) )
|
|
{
|
|
if ( GetGameplayManager()->GetGameType() == GameplayManager::GT_SUPERSPRINT )
|
|
{
|
|
collision = (!loc || loc->GetFlag( Locator::ACTIVE )) && vol->IntersectsSphere( center, 1.5f );
|
|
}
|
|
else
|
|
{
|
|
collision = (!loc || loc->GetFlag( Locator::ACTIVE )) &&
|
|
(vol->IntersectsSphere( center, 1.5f ) || vol->IntersectsBox( sP1, sP2, sP4, sP3 ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
collision = (!loc || loc->GetFlag( Locator::ACTIVE )) &&
|
|
vol->Contains( center, radius );
|
|
}
|
|
|
|
//BEGIN_PROFILE( "Test Volume" );
|
|
if ( collision )
|
|
{
|
|
//Test to see if this is a DEATH volume.
|
|
if ( loc->GetDataType() == LocatorType::EVENT )
|
|
{
|
|
EventLocator* evtLoc = static_cast<EventLocator*>(loc);
|
|
if ( evtLoc->GetEventType() == LocatorEvent::DEATH )
|
|
{
|
|
//This is so that death volumes always say you're in them until you leave.
|
|
//Hack for Chuka.
|
|
vol->Trigger( playerID, true );
|
|
return; //Early death.
|
|
}
|
|
}
|
|
|
|
//BEGIN_PROFILE( "Is Player Tracking" );
|
|
if ( !vol->IsPlayerTracking( playerID ) )
|
|
{
|
|
//New trigger!
|
|
#ifdef RAD_DEBUG
|
|
char name[256];
|
|
sprintf(name, "Hit trigger: %s\n", vol->GetName() );
|
|
rDebugString( name );
|
|
#endif
|
|
|
|
if ( playerID < MAX_PLAYERS )
|
|
{
|
|
//BEGIN_PROFILE( "AddActive" );
|
|
AddActive( playerID, vol );
|
|
//END_PROFILE( "AddActive" );
|
|
}
|
|
else
|
|
{
|
|
AddAIActive( playerID - MAX_PLAYERS, vol );
|
|
}
|
|
}
|
|
|
|
vol->SetFrameUsed( time, (int)this );
|
|
}
|
|
//END_PROFILE( "Test Volume" );
|
|
}
|