The-Simpsons-Hit-and-Run/game/code/camera/supercam.cpp

1544 lines
46 KiB
C++

//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: supercam.cpp
//
// Description: Implement SuperCam
//
// History: 03/04/2002 + Created -- Cary Brisebois
//
//=============================================================================
//========================================
// System Includes
//========================================
// Foundation Tech
//These are included in the precompiled headers on XBOX and GC
#include <raddebug.hpp>
#include <raddebugwatch.hpp>
#include <radmath/radmath.hpp>
#include <camera/supercamcontroller.h>
#include <input/inputmanager.h>
#ifdef WORLD_BUILDER
#include "main/toolhack.h"
#endif
#include <p3d/pointcamera.hpp>
//========================================
// Project Includes
//========================================
#ifndef WORLD_BUILDER
#include <camera/SuperCam.h>
#include <camera/icamerashaker.h>
#include <camera/supercamconstants.h>
#include <memory/srrmemory.h>
#else
#include "SuperCam.h"
#include "icamerashaker.h"
#include "supercamconstants.h"
#define MEMTRACK_PUSH_GROUP(x)
#define MEMTRACK_POP_GROUP(x)
#endif
//*****************************************************************************
//
// Global Data, Local Data, Local Classes
//
//*****************************************************************************
// DEFAULTS
//const float SUPERCAM_FOV = 1.57079f; //90 Degrees
//const float SUPERCAM_ASPECT = 4.0f / 3.0f; //Standard aspect ratio
//const float SUPERCAM_NEAR = 0.1f;
//const float SUPERCAM_FAR = 20000.0f;
const float CAMERA_DEAD_ZONE = 0.02f; //This is a controller dead zone
const float CAMERA_ROTATE_SPEED = 0.01f; //How fast to rotate camera
#ifdef DEBUGWATCH
unsigned int TRANSITION_TIME_LIMIT = 0; //This is in miliseconds
float FOV_TRANSITION_RATE = 0.122f;
float MAX_MODIFIER = 30.0f;
#else
//NOTE!!!!
//The values for TRANSITION_RATE and TARGET_TRANSITION RATE should be very close!!!
//How close? Within 0.001 or you will get some strange effects when transitioning!
const unsigned int TRANSITION_TIME_LIMIT = 0; //This is in miliseconds
const float FOV_TRANSITION_RATE = 0.122f;
const float MAX_MODIFIER = 30.0f;
#endif
const float TRANSITION_RATE = 0.02f;
const float TARGET_TRANSITION_RATE = 0.02f;
unsigned int SuperCam::s_secondaryControllerID = 1;
//*****************************************************************************
//
// Public Member Functions
//
//*****************************************************************************
//=============================================================================
// SuperCam::SuperCam
//=============================================================================
// Description: Constructor.
//
// Parameters: None.
//
// Return: N/A.
//
//=============================================================================
SuperCam::SuperCam() :
mFlags( 0 ),
mController( NULL ),
mControllerHandle( -1 ),
mCamera( NULL ),
mSCFOV( SUPERCAM_FOV ),
mSCAspect( SUPERCAM_ASPECT ),
mSCNearPlane( SUPERCAM_NEAR ),
mSCFarPlane( SUPERCAM_FAR ),
mCameraVirtualFOV( 0.0f ),
mCameraVirtualFOVDelta( 0.0f ),
mTransitionTime( 0 ),
mTransitionTimeLimit( TRANSITION_TIME_LIMIT ),
mTransitionPositionRate( TRANSITION_RATE ),
mTransitionTargetRate( TARGET_TRANSITION_RATE ),
mFOVTransitionRate( FOV_TRANSITION_RATE ),
mShaker( NULL ),
mPlayerID( -1 ),
mSCBackupFOV( SUPERCAM_FOV ),
mSCTwist( 0.0f ),
mOldTwist( 0.0f ),
mTwistDelta( 0.0f ),
mTwistLag( 0.01f )
{
//This get set automatically for all camera's. It's up to the camera
//to care if this is set or not. And to clear it.
SetFlag( FIRST_TIME, true );
SetFlag( DIRTY_HEADING, true );
mVelocity.Set(0.0f,0.0f,0.0f);
mCameraVirtualPosition.Set(0.0f,0.0f,0.0f);
mCameraVirtualTarget.Set(0.0f,0.0f,0.0f);
mCameraVirtualPositionDelta.Set(0.0f,0.0f,0.0f);
mCameraVirtualTargetDelta.Set(0.0f,0.0f,0.0f);
mNormalizedHeading.Set(0.0f, 0.0f, 1.0f);
#ifndef WORLD_BUILDER
if(p3d::display->IsWidescreen())
{
mSCAspect = ( 16.0f / 9.0f );
}
#endif
}
//=============================================================================
// SuperCam::~SuperCam
//=============================================================================
// Description: Destructor.
//
// Parameters: None.
//
// Return: N/A.
//
//=============================================================================
SuperCam::~SuperCam()
{
if ( mCamera )
{
mCamera->Release();
}
if ( mController )
{
InputManager* im = InputManager::GetInstance();
rAssert( im );
int controllerID = GetInputManager()->GetControllerIDforPlayer( this->GetPlayerID() );
im->UnregisterMappable( static_cast<unsigned int>( controllerID ), mControllerHandle );
mController->Release();
}
}
//=============================================================================
// SuperCam::RegisterDebugControls
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::RegisterDebugControls()
{
#ifdef DEBUGWATCH
char nameSpace[256];
sprintf( nameSpace, "SuperCam\\Player%d\\Base", GetPlayerID() );
radDbgWatchAddFloat( &mSCFOV, "FOV", nameSpace, NULL, NULL, 0, rmt::PI_2 );
radDbgWatchAddFloat( &mSCAspect, "Aspect Ratio", nameSpace, NULL, NULL, 0, 5.0f );
radDbgWatchAddFloat( &mSCNearPlane, "Near Plane", nameSpace, NULL, NULL, -1.0f, 30.0f );
radDbgWatchAddFloat( &mSCFarPlane, "Far Plane", nameSpace, NULL, NULL, 0, 20000.0f );
radDbgWatchAddUnsignedInt( &TRANSITION_TIME_LIMIT, "Transition Time", nameSpace, NULL, NULL, 0, 10000 );
radDbgWatchAddFloat( &mTransitionPositionRate, "Transition Rate", nameSpace, NULL, NULL, 0, 1.0f );
radDbgWatchAddFloat( &mTransitionTargetRate, "Target Transition Rate", nameSpace, NULL, NULL, 0, 1.0f );
radDbgWatchAddFloat( &FOV_TRANSITION_RATE, "FOV Transition Rate", nameSpace, NULL, NULL, 0, 1.0f );
radDbgWatchAddFloat( &MAX_MODIFIER, "Static|Rail max tran speed", nameSpace, NULL, NULL, 10.0f, 100.0f );
radDbgWatchAddFloat( &mSCTwist, "Camera Twist", nameSpace, NULL, NULL, 0.0f, rmt::PI_2 );
radDbgWatchAddFloat( &mTwistLag, "Camera Twist Lag", nameSpace, NULL, NULL, 0.0f, 1.0f );
#endif
OnRegisterDebugControls();
}
//=============================================================================
// SuperCam::UnregisterDebugControls
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::UnregisterDebugControls()
{
#ifdef DEBUGWATCH
radDbgWatchDelete( &mSCFOV );
radDbgWatchDelete( &mSCAspect );
radDbgWatchDelete( &mSCNearPlane );
radDbgWatchDelete( &mSCFarPlane );
radDbgWatchDelete( &TRANSITION_TIME_LIMIT );
radDbgWatchDelete( &mTransitionPositionRate );
radDbgWatchDelete( &mTransitionTargetRate );
radDbgWatchDelete( &FOV_TRANSITION_RATE );
radDbgWatchDelete( &MAX_MODIFIER );
radDbgWatchDelete( &mSCTwist );
radDbgWatchDelete( &mTwistLag );
#endif
OnUnregisterDebugControls();
}
//=============================================================================
// SuperCam::GetPosition
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* position )
//
// Return: void
//
//=============================================================================
void SuperCam::GetPosition( rmt::Vector* position ) const
{
if( mCamera )
{
if ( GetFlag( (Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
*position = mCameraVirtualPosition;
}
else
{
mCamera->GetPosition( position );
}
}
else
{
position->Set( 0.0f, 0.0f, 0.0f );
}
}
//=============================================================================
// SuperCam::GetTarget
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* target )
//
// Return: void
//
//=============================================================================
void SuperCam::GetTarget( rmt::Vector* target ) const
{
if( mCamera )
{
if ( GetFlag( (Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
*target = mCameraVirtualTarget;
}
else
{
mCamera->GetTarget( target );
}
}
else
{
target->Set(0,0,0);
}
}
//=============================================================================
// SuperCam::GetHeading
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* heading )
//
// Return: void
//
//=============================================================================
void SuperCam::GetHeading( rmt::Vector* heading ) const
{
if ( mCamera )
{
rmt::Vector pos, targ;
if ( GetFlag((Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
pos = mCameraVirtualPosition;
targ = mCameraVirtualTarget;
}
else
{
mCamera->GetPosition( &pos );
mCamera->GetTarget( &targ );
}
heading->Sub( targ, pos );
}
else
{
heading->Set(0,0,0);
}
}
//=============================================================================
// SuperCam::GetHeadingNormalized
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* heading )
//
// Return: void
//
//=============================================================================
void SuperCam::GetHeadingNormalized( rmt::Vector* heading )
{
rAssert( mCamera );
if ( GetFlag((Flag)DIRTY_HEADING) )
{
GetHeading( &mNormalizedHeading );
mNormalizedHeading.Normalize();
SetFlag((Flag)DIRTY_HEADING, false);
}
rAssert(mNormalizedHeading.MagnitudeSqr() != 0.0f);
*heading = mNormalizedHeading;
}
//=============================================================================
// SuperCam::GetCameraUp
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* up )
//
// Return: void
//
//=============================================================================
void SuperCam::GetCameraUp( rmt::Vector* up ) const
{
if ( mCamera )
{
//This shouldn't change during the SHAKE or TRANSITION
mCamera->GetVUp( up );
}
else
{
up->Set(0,0,0);
}
}
//=============================================================================
// SuperCam::SetFOV
//=============================================================================
// Description: Comment
//
// Parameters: ( float FOVinRadians )
//
// Return: void
//
//=============================================================================
void SuperCam::SetFOV( float FOVinRadians )
{
if ( GetFlag((Flag)OVERRIDE_FOV ) )
{
//We' are overriding, this will be the regular FOV
//when we're done
mSCBackupFOV = FOVinRadians;
}
else if ( GetFlag( (Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
//Middle of transition.
mCameraVirtualFOV = FOVinRadians;
mCameraVirtualFOVDelta = 0.0f;
}
else
{
//The is the regular FOV of the camera.
mSCFOV = FOVinRadians;
}
}
//=============================================================================
// SuperCam::GetFOV
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: float (in radians)
//
//=============================================================================
float SuperCam::GetFOV() const
{
if ( GetFlag((Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
return mCameraVirtualFOV;
}
else
{
return mSCFOV;
}
}
//=============================================================================
// SuperCam::Display
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::Display() const
{
#ifdef SUPERCAM_DEBUG
//We could display the name of the camera or something.
OnDisplay();
#endif
}
//*****************************************************************************
//
// Protected Member Functions
//
//*****************************************************************************
//==============================================================================
// SuperCam::SetCameraValues
//==============================================================================
// Description: This is the best way to change the position and target of the
// camera. If you do not pass in a VUP vector one will be
// calculated for you.
// Also, if DEBUG is defined then the values of the camera matrix
// will be checked.
//
// Parameters: ( unsigned int milliseconds,
// rmt::Vector pos,
// rmt::Vector targ,
// const rmt::Vector* vup )
//
// Return: void
//
//==============================================================================
void SuperCam::SetCameraValues( unsigned int milliseconds,
rmt::Vector pos,
rmt::Vector targ,
const rmt::Vector* vup )
{
#ifdef PROFILER_ENABLED
char sCname[256];
sprintf( sCname, "SC: %d SetCameraValues", mPlayerID );
BEGIN_PROFILE( sCname )
#endif
rAssert( !rmt::Epsilon( pos.MagnitudeSqr(), 0.0f, 0.01f ) );
CorrectDist( pos, targ );
rAssertMsg( mPlayerID >= 0, "You need to set a player ID before anyting else!" );
rAssertMsg( !(GetFlag( (Flag)SHAKE ) && GetFlag( (Flag)TRANSITION )), "Do not shake the camera while transitioning!" );
if ( GetFlag( (Flag)START_SHAKE ) )
{
SetupShake();
}
else if ( GetFlag( (Flag)END_SHAKE ) )
{
EndShake();
}
else if ( GetFlag( (Flag)START_TRANSITION ) )
{
SetupTransition();
}
else if ( GetFlag( (Flag)END_TRANSITION ) )
{
EndTransition();
}
//Calculate the velocity of the camera
rmt::Vector oldPos;
GetPosition( &oldPos );
if ( GetFlag( (Flag)SHAKE ) || GetFlag( (Flag)TRANSITION ) )
{
//If we're doing an ease in, we don't do this...
if ( !GetFlag( (Flag)EASE_IN ) )
{
//Store the position that the super cam THINKS it's at...
mCameraVirtualPosition = pos;
mCameraVirtualTarget = targ;
}
if ( GetFlag( (Flag)SHAKE ) )
{
mShaker->ShakeCamera( &pos, &targ, milliseconds );
}
else
{
if ( GetFlag( (Flag)EASE_IN ) )
{
if( mTransitionPositionRate >= 1.0f )
{
//Hackish
//Emulate a cut... Clean this up sometime eh?
mTransitionTime = mTransitionTimeLimit - 1;
}
else
{
float timeMod = rmt::LtoF(milliseconds) / EXPECTED_FRAME_RATE;
float timeEffect = MAX_MODIFIER * mTransitionPositionRate;
//Also take into account the target's velocity.
//This allows us to transition faster when the character is
//moving quickly.
timeEffect *= GetTargetSpeedModifier();
rDebugPrintf( "timeEffect: %.4f\n", timeEffect );
mTransitionTime += rmt::FtoL((rmt::LtoF(milliseconds) * timeEffect));
}
}
else
{
mTransitionTime += milliseconds;
}
rmt::Vector distPos, distTarg;
rmt::Vector actPos, actTarg;
mCamera->GetPosition( &actPos );
mCamera->GetTarget( &actTarg );
distPos.Sub( pos, actPos );
distTarg.Sub( targ, actTarg );
if ( mTransitionTime >= mTransitionTimeLimit ||
(rmt::Epsilon( distPos.MagnitudeSqr(), 0.0f, 0.001f ) &&
rmt::Epsilon( distTarg.MagnitudeSqr(), 0.0f, 0.001f ) &&
rmt::Epsilon( mSCFOV, mCameraVirtualFOV, 0.001f ) )
)
{
//Turn it off now.
SetFlag( (Flag)END_TRANSITION, true );
EndTransition();
}
else
{
if ( GetFlag( (Flag)EASE_IN ) )
{
//Do the Ease in
EaseIn( rmt::LtoF(mTransitionTime) / rmt::LtoF(mTransitionTimeLimit), &pos, &targ, milliseconds );
TransitionFOV( rmt::LtoF(mTransitionTime) / rmt::LtoF(mTransitionTimeLimit), &mSCFOV, milliseconds );
}
else
{
//Do the Transition
TransitionCamera( rmt::LtoF(mTransitionTime) / rmt::LtoF(mTransitionTimeLimit), &pos, &targ, &mSCFOV, milliseconds, GetFlag( (Flag)QUICK_TRANSITION ) );
}
}
}
}
//Better place for the velocity calculation.
mVelocity.Sub( pos, oldPos );
//Update the position of the camera and set the VUP
mCamera->SetPosition( pos );
mCamera->SetTarget( targ );
SetFlag((Flag)DIRTY_HEADING, true);
if ( vup )
{
mCamera->SetVUp( *vup );
}
else
{
mCamera->SetVUp( UpdateVUP( pos, targ ) );
}
//This will be cool in the halloween level
float oldTwist = mCamera->GetTwist();
if ( !rmt::Epsilon( mSCTwist, oldTwist, 0.001f ) )
{
AdjustAngles( &mSCTwist, &oldTwist, &mTwistDelta );
MotionCubic( &oldTwist, &mTwistDelta, mSCTwist, mTwistLag );
}
mCamera->SetTwist( oldTwist );
//Write the overriding FOV, aspect and near and far planes.
mCamera->SetFOV( mSCFOV, mSCAspect );
mCamera->SetNearPlane( mSCNearPlane );
mCamera->SetFarPlane( mSCFarPlane );
#ifdef RAD_DEBUG
TestCameraMatrix();
#endif
#ifdef PROFILER_ENABLED
END_PROFILE( sCname )
#endif
// char out[256];
// sprintf( out, "pos: %.2f, %.2f, %.2f targ: %.2f, %.2f, %.2f\n", pos.x, pos.y, pos.z, targ.x, targ.y, targ.z );
// rDebugString( out );
}
//=============================================================================
// SuperCam::OverrideFOV
//=============================================================================
// Description: Comment
//
// Parameters: ( bool enable, float time )
//
// Return: void
//
//=============================================================================
void SuperCam::OverrideFOV( bool enable, float time, float rate )
{
if ( enable != GetFlag( (Flag)OVERRIDE_FOV ) )
{
//Toggling
if ( enable )
{
//Turning on.
if ( GetFlag( (Flag)TRANSITION ) )
{
//Switch the stored override value for the current regular value
//which is stored in the virtual fov since we're tansitioning.
float tempFOV = mSCBackupFOV;
mSCBackupFOV = mCameraVirtualFOV;
mCameraVirtualFOV = tempFOV;
}
else
{
//Swap the regular fov for the stored override FOV
float tempFOV = mSCBackupFOV;
mSCBackupFOV = mSCFOV;
mSCFOV = tempFOV;
}
}
else
{
//Bring the regular FOV value back.
if ( GetFlag( (Flag)TRANSITION ) )
{
mCameraVirtualFOV = mSCBackupFOV;
}
else
{
mSCFOV = mSCBackupFOV;
}
//Clear out the stored FOV.
mSCBackupFOV = 0.0f;
}
//Use the transition system to transition the
//fov..
mTransitionTimeLimit = rmt::FtoL(time * 1000.0f);
mFOVTransitionRate = rate;
SetFlag( (Flag)OVERRIDE_FOV, enable );
if ( !GetFlag((Flag)TRANSITION ) )
{
SetupTransition( true );
}
}
}
//=============================================================================
// SuperCam::DisableOverride
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::DisableOverride()
{
if ( GetFlag( (Flag)OVERRIDE_FOV ) )
{
if ( GetFlag( (Flag)TRANSITION ) )
{
mCameraVirtualFOV = mSCBackupFOV;
}
else
{
mSCFOV = mSCBackupFOV;
}
mSCBackupFOV = 0.0f;
SetFlag( (Flag)OVERRIDE_FOV, false );
}
}
//=============================================================================
// SuperCam::SetFOVOverride
//=============================================================================
// Description: Comment
//
// Parameters: ( float newFOV )
//
// Return: void
//
//=============================================================================
void SuperCam::SetFOVOverride( float newFOV )
{
if ( GetFlag( (Flag)OVERRIDE_FOV) )
{
if ( GetFlag( (Flag)TRANSITION ) )
{
//Middle of a transition, set the virtual FOV...
mCameraVirtualFOV = newFOV;
mCameraVirtualFOVDelta = 0.0f; //Must reset when we change this!
}
else
{
//Already overriding, need to set a new number
mSCFOV = newFOV;
}
}
else
{
//Hang on to the override until we need it.
mSCBackupFOV = newFOV;
}
}
//=============================================================================
// SuperCam::SetCamera
//=============================================================================
// Description: Comment
//
// Parameters: ( tPointCamera* cam )
//
// Return: void
//
//=============================================================================
void SuperCam::SetCamera( tPointCamera* cam )
{
if ( mCamera )
{
mCamera->Release();
}
mCamera = cam;
mCamera->AddRef();
}
//=============================================================================
// SuperCam::ClampAngle
//=============================================================================
// Description: Comment
//
// Parameters: ( float* angle, bool* clamped )
//
// Return: int (This number of times PI_2 was added
//
//=============================================================================
int SuperCam::ClampAngle( float* angle ) const
{
int total = 0;
if ( *angle < 0.0f )
{
do
{
//Add 360 until the number is positive
*angle += rmt::PI_2;
++total;
}
while ( *angle < 0.0f );
}
else if ( *angle > rmt::PI_2 )
{
do
{
//Subtract 360 until number is <= 360
*angle -= rmt::PI_2;
--total;
}
while ( *angle > rmt::PI_2 );
}
return total;
}
//=============================================================================
// SuperCam::AdjustAngles
//=============================================================================
// Description: Comment
//
// Parameters: ( float* desiredAngle,
// float* currentAngle,
// float* curentAngleDelta )
//
// Return: void
//
//=============================================================================
void SuperCam::AdjustAngles( float* desiredAngle,
float* currentAngle,
float* currentAngleDelta ) const
{
//First we should get all values within 0 360 ( 0 - 2 PI )
ClampAngle( desiredAngle );
ClampAngle( currentAngle );
//We only want to interpolate to a rotation via the fewest number of degrees.
if ( rmt::Fabs( *desiredAngle - *currentAngle ) > rmt::PI ) //More than 180deg
{
//They are too far apart, which way to rotate?
if ( *desiredAngle - *currentAngle < 0.0f )
{
//desiredAngle is bigger than currentAngle by >= 180 deg
//rotate towards 0
//Add 360 deg
*desiredAngle += rmt::PI_2;
}
else
{
//desiredAngle is smaller than currentAngle by >= 180 deg
//rotate away from 0
//Subtract 360 deg
*desiredAngle -= rmt::PI_2;
}
}
}
//=============================================================================
// SuperCam::Shutdown
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::Shutdown()
{
DisableOverride();
EndTransition( true );
ShutDownMyController();
OnShutdown(); //Tell the child..
}
//=============================================================================
// SuperCam::CorrectDist
//=============================================================================
// Description: Comment
//
// Parameters: ( const rmt::Vector& pos, rmt::Vector& targ )
//
// Return: void
//
//=============================================================================
void SuperCam::CorrectDist( const rmt::Vector& pos, rmt::Vector& targ )
{
//Make sure pos and target aren't too close!
rmt::Vector pos2targ;
pos2targ.Sub( targ, pos );
if ( pos2targ.MagnitudeSqr() < 1.0f )
{
pos2targ.NormalizeSafe();
pos2targ.Scale( 1.0f );
targ.Add( pos, pos2targ );
// rDebugString( "\n\nWARNING! Adjusting camera targ as it is too close to the position!\n\n" );
}
}
//=============================================================================
// SuperCam::InitMyController
//=============================================================================
// Description: Comment
//
// Parameters: ( int controllerID )
//
// Return: void
//
//=============================================================================
void SuperCam::InitMyController( int controllerID )
{
MEMTRACK_PUSH_GROUP( "SuperCam" );
if ( mController == NULL )
{
mController = new SuperCamController();
rAssert( mController );
mController->AddRef();
}
if ( mControllerHandle == -1 )
{
InputManager* im = InputManager::GetInstance();
rAssert( im );
if ( controllerID == -1 )
{
//Get a new one, otherwise use the passed in one.
controllerID = GetInputManager()->GetControllerIDforPlayer( this->GetPlayerID() );
}
if (controllerID != -1 )
{
mControllerHandle = im->RegisterMappable( static_cast<unsigned int>( controllerID ), mController );
}
}
MEMTRACK_POP_GROUP("SuperCam");
}
//=============================================================================
// SuperCam::ShutDownMyController
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::ShutDownMyController()
{
if ( mControllerHandle != -1 )
{
InputManager* im = InputManager::GetInstance();
rAssert( im );
rTuneAssert( mControllerHandle != -1 );
int controllerID = GetInputManager()->GetControllerIDforPlayer( this->GetPlayerID() );
im->UnregisterMappable( static_cast<unsigned int>( controllerID ), mController );
mControllerHandle = -1;
}
}
//=============================================================================
// SuperCam::GetCameraNonConst
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: tPointCamera
//
//=============================================================================
tPointCamera* SuperCam::GetCameraNonConst()
{
return mCamera;
}
//=============================================================================
// SuperCam::SphericalMotion
//=============================================================================
// Description: Comment
//
// Parameters: ( const rmt::Vector& target,
// rmt::Vector& currentPos,
// rmt::Vector& desiredPos,
// rmt::Vector& desiredPosDelta,
// float rate,
// float timeMod )
//
// Return: void
//
//=============================================================================
void SuperCam::SphericalMotion( const rmt::Vector& target,
rmt::Vector& currentPos,
const rmt::Vector& desiredPos,
rmt::Vector& desiredPosDelta,
const float rate ) const
{
#ifdef PROFILER_ENABLED
char sCname[256];
sprintf( sCname, "SC: %d Spherical Motion", mPlayerID );
BEGIN_PROFILE( sCname )
#endif
rmt::Vector virtTargToPos;
rmt::Vector virtTargToVirtPos;
virtTargToPos.Sub( currentPos, target );
virtTargToVirtPos.Sub( desiredPos, target );
float actRot, actElev, actMag;
float virtRot, virtElev, virtMag;
rmt::CartesianToSpherical( virtTargToPos.x, virtTargToPos.z, virtTargToPos.y, &actMag, &actRot, &actElev );
rmt::CartesianToSpherical( virtTargToVirtPos.x, virtTargToVirtPos.z, virtTargToVirtPos.y, &virtMag, &virtRot, &virtElev );
//Clean up the angles.
AdjustAngles( &virtRot, &actRot, &desiredPosDelta.x );
AdjustAngles( &actElev, &actElev, &desiredPosDelta.y );
MotionCubic( &actRot, &desiredPosDelta.x, virtRot, rate );
MotionCubic( &actElev, &desiredPosDelta.y, virtElev, rate );
MotionCubic( &actMag, &desiredPosDelta.z, virtMag, rate );
rmt::Vector newPos;
rmt::SphericalToCartesian( actMag, actRot, actElev, &newPos.x, &newPos.z, &newPos.y );
currentPos = newPos;
#ifdef PROFILER_ENABLED
END_PROFILE( sCname )
#endif
}
//=============================================================================
// SuperCam::UpdateVUP
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector position, rmt::Vector target )
//
// Return: rmt::Vector
//
//=============================================================================
rmt::Vector SuperCam::UpdateVUP( rmt::Vector position, rmt::Vector target )
{
#ifdef PROFILER_ENABLED
char sCname[256];
sprintf( sCname, "SC: %d UpdateVUP", mPlayerID );
BEGIN_PROFILE( sCname )
#endif
const float epsilon = 0.01f;
//Set the vUP by projecting the heading into the ZX plane and creating a
//crossproduct of a right angle to the projected heading along the X axis
//and the heading.
rmt::Vector CamX, CamY, CamZ;
CamZ.Sub(target, position);
CamX.Set(CamZ.z, 0, -CamZ.x);
if ( rmt::Epsilon( CamX.x, 0, epsilon ) &&
rmt::Epsilon( CamX.y, 0, epsilon ) &&
rmt::Epsilon( CamX.z, 0, epsilon ) )
{
//Then the camera is looking straight down.
CamY.Set( 0, 0, 1.0f ); //Up along the Z...
}
else
{
CamY.CrossProduct(CamZ, CamX);
CamY.Normalize();
}
#ifdef PROFILER_ENABLED
END_PROFILE( sCname )
#endif
return CamY;
}
//=============================================================================
// SuperCam::EaseMotion
//=============================================================================
// Description: Parabolic ease-in / ease-out
// The default case of no ease-in/ease-out would produce a velocity
// curve that is a horizontal straight line of vec0 as t goes from 0
// to 1. The distance covered would be ease(1) = vec0*1.
// Assume constant acceleration and deceleration at the beginning
// and end of the motion, and zero acceleration during the middle
// of the motion. t is parametric time ( 0 - 1 ), a and b are times
// when acceleration ends and deceleration begins.
//
// Parameters: ( float t, float a, float b )
//
// Return: float
//
//=============================================================================
float SuperCam::EaseMotion( float t, float a, float b )
{
float vec0, d;
vec0 = 2.0f / ( 1 + b - a ); //Constant velocity attained.
if ( t < a )
{
d = vec0 * t * t / ( 2.0f * a );
}
else
{
d = vec0 * a / 2.0f;
if ( t < b )
{
d += ( t - a ) / 2.0f;
}
else
{
d += ( b - a ) * vec0;
d += ( t - t * t / 2.0f - b + b * b / 2.0f ) * vec0 / ( 1 - b );
}
}
return d;
}
//*****************************************************************************
//
// Private Member Functions
//
//*****************************************************************************
//=============================================================================
// SuperCam::DoCameraTransition
//=============================================================================
// Description: Comment
//
// Parameters: ( bool quick, unsigned int timems )
//
// Return: void
//
//=============================================================================
void SuperCam::DoCameraTransition( bool quick, unsigned int timems )
{
if ( GetFlag( (Flag)CUT ) )
{
//Let's not transition if we're waiting to cut.
return;
}
#ifdef DEBUGWATCH
if ( TRANSITION_TIME_LIMIT > 0 )
{
//Override the time limit by the watcher value.
timems = TRANSITION_TIME_LIMIT;
}
#endif
mTransitionTimeLimit = timems;
if ( GetFlag((Flag)SHAKE ) )
{
//Hmmmm... This could be a hack.
EndShake();
}
SetFlag( (Flag)START_TRANSITION, true );
if ( quick )
{
SetFlag( (Flag)QUICK_TRANSITION, true );
}
if ( GetType() == STATIC_CAM || GetType() == RAIL_CAM )
{
SetFlag( (Flag)EASE_IN, true );
}
}
//=============================================================================
// SuperCam::TestCameraMatrix
//=============================================================================
// Description: This is the only way to tell when the camera gets a bad
// setting that will blow up the game.
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::TestCameraMatrix()
{
#ifdef PROFILER_ENABLED
char sCname[256];
sprintf( sCname, "SC: %d TestCameraMatrix", mPlayerID );
BEGIN_PROFILE( sCname )
#endif
const rmt::Matrix c2w = mCamera->GetWorldToCameraMatrix();
int i, j;
for( i = 0; i < 4; i++ )
{
for( j = 0; j < 4; j++ )
{
rAssertMsg( !rmt::IsNan(c2w.m[i][j]), "This is a bad matrix for the super cam!");
}
}
#ifdef PROFILER_ENABLED
END_PROFILE( sCname )
#endif
}
//=============================================================================
// SuperCam::SetupShake
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::SetupShake()
{
if ( !GetFlag( (Flag)SHAKE ) && mShaker )
{
rmt::Vector oldPos;
GetPosition( &oldPos );
mCameraVirtualPosition = oldPos;
SetFlag( (Flag)START_SHAKE, false );
SetFlag( (Flag)SHAKE, true );
rAssert( mShaker );
mShaker->SetCamera( mCamera );
mShaker->SetSpeed( 1.0f );
mShaker->RegisterDebugInfo();
}
}
//=============================================================================
// SuperCam::EndShake
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void SuperCam::EndShake()
{
if ( GetFlag( (Flag)SHAKE ) )
{
mCamera->SetPosition( mCameraVirtualPosition );
mCamera->SetTarget( mCameraVirtualTarget );
mCameraVirtualPosition.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualTarget.Set(0.0f, 0.0f, 0.0f);
SetFlag( (Flag)START_SHAKE, false );
SetFlag( (Flag)SHAKE, false );
SetFlag( (Flag)END_SHAKE, false );
mShaker->UnregisterDebugInfo();
mShaker = NULL;
}
}
//=============================================================================
// SuperCam::SetupTransition
//=============================================================================
// Description: Comment
//
// Parameters: ( bool swap )
//
// Return: void
//
//=============================================================================
void SuperCam::SetupTransition( bool swap )
{
if ( !GetFlag( (Flag)TRANSITION ) )
{
rmt::Vector oldPos, oldTarget;
GetPosition( &oldPos );
mCameraVirtualPosition = oldPos;
GetTarget( &oldTarget );
mCameraVirtualTarget = oldTarget;
if ( swap )
{
float temp = mCameraVirtualFOV;
mCameraVirtualFOV = mSCFOV;
mSCFOV = temp;
}
else
{
mCameraVirtualFOV = mSCFOV;
float waste = 0.0f;
mCamera->GetFOV( &mSCFOV, &waste );
}
SetFlag( (Flag)TRANSITION, true );
}
mTransitionTime = 0;
mCameraVirtualPositionDelta.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualTargetDelta.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualFOVDelta = 0.0f;
SetFlag( (Flag)START_TRANSITION, false );
}
//=============================================================================
// SuperCam::EndTransition
//=============================================================================
// Description: Comment
//
// Parameters: ( bool abort )
//
// Return: void
//
//=============================================================================
void SuperCam::EndTransition( bool abort )
{
if ( GetFlag( (Flag)TRANSITION ) )
{
if ( !abort )
{
mCamera->SetPosition( mCameraVirtualPosition );
mCamera->SetTarget( mCameraVirtualTarget );
mSCFOV = mCameraVirtualFOV;
}
mCameraVirtualPosition.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualTarget.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualPositionDelta.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualTargetDelta.Set(0.0f, 0.0f, 0.0f);
mCameraVirtualFOVDelta = 0.0f;
mTransitionTimeLimit = TRANSITION_TIME_LIMIT;
mFOVTransitionRate = FOV_TRANSITION_RATE;
SetFlag( (Flag)TRANSITION, false );
SetFlag( (Flag)END_TRANSITION, false );
SetFlag( (Flag)QUICK_TRANSITION, false );
}
SetFlag( (Flag)START_TRANSITION, false );
}
//=============================================================================
// SuperCam::ShakeCamera
//=============================================================================
// Description: Comment
//
// Parameters: ( rmt::Vector* pos, rmt::Vector* targ, unsigned int milliseconds )
//
// Return: void
//
//=============================================================================
void SuperCam::ShakeCamera( rmt::Vector* pos,
rmt::Vector* targ,
unsigned int milliseconds )
{
if ( mShaker )
{
if ( !mShaker->DoneShaking() )
{
mShaker->ShakeCamera( pos, targ, milliseconds );
if ( mShaker->DoneShaking() )
{
DisableShake();
}
}
}
}
//=============================================================================
// SuperCam::TransitionCamera
//=============================================================================
// Description: Comment
//
// Parameters: ( float timeLeftPct, rmt::Vector* pos, rmt::Vector* targ, float* fov, unsigned int milliseconds, bool quick )
//
// Return: void
//
//=============================================================================
void SuperCam::TransitionCamera( float timeLeftPct,
rmt::Vector* pos,
rmt::Vector* targ,
float* fov,
unsigned int milliseconds,
bool quick )
{
//This is to adjust interpolation when we're running substeps.
float timeMod = (float)milliseconds / EXPECTED_FRAME_RATE;
float posInterval = ( ( ( 1.0f - mTransitionPositionRate ) * timeLeftPct ) + mTransitionPositionRate ) * timeMod;
CLAMP_TO_ONE(posInterval);
float targInterval = ( ( ( 1.0f - mTransitionTargetRate ) * timeLeftPct ) + mTransitionTargetRate )* timeMod;
CLAMP_TO_ONE(targInterval);
rmt::Vector actPos, actTarg;
mCamera->GetPosition( &actPos );
mCamera->GetTarget( &actTarg );
if ( !quick )
{
//Calculate the new position
SphericalMotion( mCameraVirtualTarget, actPos, mCameraVirtualPosition, mCameraVirtualPositionDelta, posInterval );
actPos.Add( actPos, mCameraVirtualTarget );
}
else
{
//Do it quick.
MotionCubic( &actPos.x, &mCameraVirtualPositionDelta.x, mCameraVirtualPosition.x, posInterval );
MotionCubic( &actPos.y, &mCameraVirtualPositionDelta.y, mCameraVirtualPosition.y, posInterval );
MotionCubic( &actPos.z, &mCameraVirtualPositionDelta.z, mCameraVirtualPosition.z, posInterval );
}
//Calculate the new targetPosition
MotionCubic( &actTarg.x, &mCameraVirtualTargetDelta.x, mCameraVirtualTarget.x, targInterval );
MotionCubic( &actTarg.y, &mCameraVirtualTargetDelta.y, mCameraVirtualTarget.y, targInterval );
MotionCubic( &actTarg.z, &mCameraVirtualTargetDelta.z, mCameraVirtualTarget.z, targInterval );
float actFOV, actAspect;
GetCamera()->GetFOV( &actFOV, &actAspect );
TransitionFOV( timeLeftPct, &actFOV, milliseconds );
*pos = actPos;
*targ = actTarg;
*fov = actFOV;
}
//=============================================================================
// SuperCam::TransitionFOV
//=============================================================================
// Description: Comment
//
// Parameters: ( float timeLeftPct, float* fov, unsigned int milliseconds )
//
// Return: void
//
//=============================================================================
void SuperCam::TransitionFOV( float timeLeftPct, float* fov, unsigned int milliseconds )
{
//This is to adjust interpolation when we're running substeps.
float timeMod = (float)milliseconds / EXPECTED_FRAME_RATE;
float fovInterval = ( ( ( 1.0f - mFOVTransitionRate ) * timeLeftPct ) + mFOVTransitionRate ) * timeMod;
CLAMP_TO_ONE(fovInterval);
//Calculate the new FOV
MotionCubic( fov, &mCameraVirtualFOVDelta, mCameraVirtualFOV, fovInterval );
}
//=============================================================================
// SuperCam::EaseIn
//=============================================================================
// Description: Comment
//
// Parameters: ( float timeLeftPct, rmt::Vector* pos, rmt::Vector* targ, unsigned int milliseconds )
//
// Return: void
//
//=============================================================================
void SuperCam::EaseIn( float timeLeftPct, rmt::Vector* pos, rmt::Vector* targ, unsigned int milliseconds )
{
float d = EaseMotion( timeLeftPct, 0.0f, 0.0f );
// char out[256];
// sprintf( out, "T = %.2f, D = %.2f\n", timeLeftPct, d );
// rDebugString( out );
pos->x = ( pos->x - mCameraVirtualPosition.x ) * d + mCameraVirtualPosition.x;
pos->y = ( pos->y - mCameraVirtualPosition.y ) * d + mCameraVirtualPosition.y;
pos->z = ( pos->z - mCameraVirtualPosition.z ) * d + mCameraVirtualPosition.z;
targ->x = ( targ->x - mCameraVirtualTarget.x ) * d + mCameraVirtualTarget.x;
targ->y = ( targ->y - mCameraVirtualTarget.y ) * d + mCameraVirtualTarget.y;
targ->z = ( targ->z - mCameraVirtualTarget.z ) * d + mCameraVirtualTarget.z;
}
//=============================================================================
// SuperCam::SetCameraShakerData
//=============================================================================
// Description: Comment
//
// Parameters: ( const ShakeEventData* data )
//
// Return: void
//
//=============================================================================
void SuperCam::SetCameraShakerData( const ShakeEventData* data )
{
if ( mShaker )
{
mShaker->Reset();
mShaker->SetShakeData( data );
}
}
//=============================================================================
// SuperCam::GetWatcherName
//=============================================================================
// Description: char for identifying this object in the watcher
//
// Parameters: NONE
//
// Return: void
//
//=============================================================================
#ifdef DEBUGWATCH
const char* SuperCam::GetWatcherName() const
{
return "No Name";
}
void SuperCam::PrintClassName() const
{
const char* watcherName = GetWatcherName();
rDebugPrintf( "Camera - %s\n", watcherName );
}
#endif //DEBUGWATCH