801 lines
27 KiB
C++
801 lines
27 KiB
C++
//-----------------------------------------------------------------------------
|
|
// CameraPath.cpp
|
|
//
|
|
// Author: Squirrel Eiserloh
|
|
//
|
|
// Copyright (C) 2002 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// DESCRIPTION:
|
|
// Implementation file for the following camera-related classes:
|
|
//
|
|
// CameraPath Describes a single camera path through time -
|
|
// including camera orientation, position,
|
|
// and field-of-view - using either many simple
|
|
// reference keyframes or a few bspline nodes.
|
|
// Also owns the coordinate system through which
|
|
// all positions and orientations are transformed
|
|
// (for scripts with relative playback locales).
|
|
//
|
|
// CameraKeyFramePath The innards of a CameraPath object implemented
|
|
// using keyframes (as opposed to bspline nodes).
|
|
// Does not know about relative locales.
|
|
//
|
|
// CameraKeyFrame A single key frame item in a CameraKeyFramePath.
|
|
// Stores a time index / frame number, the camera'a
|
|
// position (as a Vector), orientation (as a
|
|
// Quaternion), and field-of-fiew (as a Scalar).
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "CameraPath.h"
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CameraKeyFrame
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CLASS_DECLARATION( Class, CameraKeyFrame, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CameraKeyFrame
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Default Constructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: N/a
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
CameraKeyFrame::CameraKeyFrame()
|
|
:
|
|
_position( Vector( 0.0f, 0.0f, 0.0f ) ),
|
|
_orientation( Quaternion( 0.0f, 0.0f, 0.0f, 1.0f ) ),
|
|
_fovDegrees( 90.0f ),
|
|
_seconds( 0.0f )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CameraKeyFrame
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Constructor( Vector, Quaternion, float )
|
|
//
|
|
// Parameters: position XYZ coordinates of camera
|
|
// orientation camera orientation as a quaternion
|
|
// fovDegrees horizontal fov of camera, in degrees
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
CameraKeyFrame::CameraKeyFrame( const Vector& position, const Quaternion& orientation, const float fovDegrees, const float seconds )
|
|
:
|
|
_position( position ),
|
|
_orientation( orientation ),
|
|
_fovDegrees( fovDegrees ),
|
|
_seconds( seconds )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: ParseFrameInfo
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Starting with the keyword "Frame", parses one single frame entry from a .KFC
|
|
// buffer (using a Script object) in its entirety.
|
|
//
|
|
// Parameters: int frameNumber, Script& cameraPathFile
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraKeyFrame::ParseFrameInfo( int frameNumber, Script& cameraPathFile, float& totalPathTime )
|
|
{
|
|
const char* token;
|
|
|
|
/// Read in the Frame number
|
|
token = cameraPathFile.GetToken( true );
|
|
if( !stricmp( token, "Frame" ) )
|
|
{
|
|
/// Make sure the frame number is the same as <frameNumber>, as expected
|
|
int actualFrame = cameraPathFile.GetInteger( false );
|
|
if( actualFrame != frameNumber )
|
|
{
|
|
cameraPathFile.error( "CameraKeyFrame::ParseFrameInfo", "Incorrect Frame number (found %d, expecting %d)\n", frameNumber, actualFrame );
|
|
return( false );
|
|
}
|
|
}
|
|
else // bad identifier
|
|
{
|
|
gi.Printf( "Unexpected token %s in camera path file (expecting \"Frame\").\n", token );
|
|
cameraPathFile.error( "CameraKeyFrame::ParseFrameInfo", "Unexpected token %s in camera path file (expecting \"Frame\").\n", token );
|
|
return( false );
|
|
}
|
|
|
|
return( ParseFrameInfoBlock( cameraPathFile, totalPathTime ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: ParseFrameInfoBlock
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Parse in a single camera key frame from a .KFC file, from '{' to '}'
|
|
//
|
|
// Parameters: Script& cameraPathFile - parse object for .KFC file
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraKeyFrame::ParseFrameInfoBlock( Script& cameraPathFile, float& totalPathTime )
|
|
{
|
|
const char* token;
|
|
float frameTimeInSeconds = DEFAULT_KEY_FRAME_LENGTH_SECONDS;
|
|
|
|
/// Read the opening bracket
|
|
token = cameraPathFile.GetToken( true );
|
|
if( *token != '{' )
|
|
{
|
|
cameraPathFile.error( "CameraKeyFrame::ParseFrameInfoBlock", "Expected '{', found \"%s\"\n", token );
|
|
return( false );
|
|
}
|
|
|
|
/// Read each entry in the Path info block
|
|
token = cameraPathFile.GetToken( true );
|
|
while( *token != '}' )
|
|
{
|
|
if( !stricmp( token, "fov" ) )
|
|
{
|
|
/// Read in the horizontal field of view (fov) for this camera key frame
|
|
_fovDegrees = cameraPathFile.GetFloat( false );
|
|
}
|
|
else if( !stricmp( token, "position" ) )
|
|
{
|
|
/// Read in the position vector for this camera key frame
|
|
_position = cameraPathFile.GetVector( false );
|
|
}
|
|
else if( !stricmp( token, "quaternion" ) )
|
|
{
|
|
/// Read in the orientation of the camera as a quaternion
|
|
float x = cameraPathFile.GetFloat( false );
|
|
float y = cameraPathFile.GetFloat( false );
|
|
float z = cameraPathFile.GetFloat( false );
|
|
float w = cameraPathFile.GetFloat( false );
|
|
_orientation.SetFromXYZW( x, y, z, w );
|
|
}
|
|
else // unknown token
|
|
{
|
|
gi.Printf( "Unexpected token %s in camera path file.\n", token );
|
|
cameraPathFile.error( "CameraKeyFrame::ParseFrameInfoBlock", "Unexpected token %s in camera path file.\n", token );
|
|
return( false );
|
|
}
|
|
|
|
token = cameraPathFile.GetToken( true );
|
|
}
|
|
|
|
_seconds = totalPathTime;
|
|
totalPathTime += frameTimeInSeconds;
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: Interpolate
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Sets the position, orientation, and fov values in the current CameraKeyFrame
|
|
// object (this) to be a weighted average of two other key frames: <before> and
|
|
// <after>, where <fraction> represents the weighting of the <after> frame (and
|
|
// 1 - fraction is the weighting of the <before> frame).
|
|
//
|
|
// Parameters: const CameraKeyFrame& before - key frame being approached as fraction -> 0
|
|
// const CameraKeyFrame& after - key frame being approached as fraction -> 1
|
|
// const float fraction - in the range [0,1]; the fraction of <after> to be used
|
|
//
|
|
// Returns: const CameraKeyFrame&
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
const CameraKeyFrame& CameraKeyFrame::Interpolate( const CameraKeyFrame& before, const CameraKeyFrame& after, const float fraction, const bool normalizeQuaternion )
|
|
{
|
|
/// Set up some convenience references
|
|
const Vector& pos1 = before.GetPosition();
|
|
const Vector& pos2 = after.GetPosition();
|
|
const Quaternion& quat1 = before.GetOrientation();
|
|
const Quaternion& quat2 = after.GetOrientation();
|
|
float fov1 = before.GetFOV();
|
|
float fov2 = after.GetFOV();
|
|
|
|
/// Calculate interpolated position, orientation, and fov values for this new frame
|
|
|
|
_position = pos1 + ( pos2 - pos1 ) * fraction; // linear componentwise interpolation
|
|
|
|
_orientation = CalcSlerp( quat1, quat2, (double) fraction ); // (hyper)spherical linear interpolation
|
|
_fovDegrees = fov1 + (fraction * (fov2 - fov1) ); // linear float interpolation
|
|
|
|
/// Check if the caller has requested the quaternion to be renormalized after interpolation (a good idea, but costly)
|
|
if( normalizeQuaternion )
|
|
_orientation.Normalize();
|
|
|
|
return( *this );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: GetEulerAngles
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Returns the orientation of the key frame in Euler angles (pitch, yaw, roll).
|
|
// Note that orientations are internally stored as quaternions, and this function
|
|
// is mainly provided as a interface useful to the surrounding Euler-centric
|
|
// Quake / Fakk / Tiki code.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns: const Vector
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
const Vector CameraKeyFrame::GetEulerAngles( void ) const
|
|
{
|
|
Vector eulerAngles;
|
|
_orientation.GetToEuler( eulerAngles );
|
|
return eulerAngles;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: TransformToPlaybackOffsets
|
|
// Class: CameraKeyFrame
|
|
//
|
|
// Description: Transforms a CameraKeyFrame object by (1) rotating it <yawOffsetDegrees> degrees
|
|
// (including orientations and positions) and then (2) translating it by
|
|
// <originOffset> world-units.
|
|
//
|
|
// Parameters: const float yawOffset - the amount of (yaw) rotation to apply
|
|
// const Vector& originOffset - the amount of translation to apply
|
|
//
|
|
// Returns: const CameraKeyFrame& - returns *this, now transformed
|
|
//
|
|
// NOTE: Because q_math.c is a C file and was written long ago, we use vec3_t and euler
|
|
// angles instead of Vector and Quaternion.
|
|
//-----------------------------------------------------------------------------------------------
|
|
const CameraKeyFrame& CameraKeyFrame::TransformToPlaybackOffsets( const float yawOffsetDegrees, const Vector& originOffset )
|
|
{
|
|
/// Rotate <_position> about the Z axis by <yawOffsetDegrees>
|
|
vec3_t zNormal = { 0.0f, 0.0f, 1.0f };
|
|
vec3_t point;
|
|
vec3_t rotated;
|
|
_position.copyTo( point ); // Don't blame me for this. Our math library was written in C.
|
|
RotatePointAroundVector( rotated, zNormal, point, yawOffsetDegrees );
|
|
_position = rotated;
|
|
|
|
/// Rotate <_orientation> in a like manner
|
|
Vector eulerOrientation;
|
|
_orientation.GetToEuler( eulerOrientation );
|
|
eulerOrientation.y += yawOffsetDegrees;
|
|
_orientation.SetFromEuler( eulerOrientation );
|
|
_orientation.Normalize();
|
|
|
|
/// Translate <_position> by <originOffset>
|
|
_position += originOffset; // see how easy things can be in C++?
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CameraKeyFramePath
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CLASS_DECLARATION( Class, CameraKeyFramePath, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CameraKeyFramePath
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Default Constructor
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
CameraKeyFramePath::CameraKeyFramePath()
|
|
:
|
|
_isLoaded( false ),
|
|
_numKeyFrames( 0 ),
|
|
_keyFrameArray( NULL ),
|
|
_totalSeconds( 0.0f )
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: Unload
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Destroys the key-framed camera path data and
|
|
// marks the object as dirty (_isLoaded = false).
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
void CameraKeyFramePath::Unload( void )
|
|
{
|
|
if( IsLoaded() )
|
|
{
|
|
delete [] _keyFrameArray;
|
|
_keyFrameArray = NULL;
|
|
}
|
|
|
|
_totalSeconds = 0.0f;
|
|
_isLoaded = false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CreateFrames
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Allocates <numberOfFrames> CameraKeyFrame objects
|
|
// in a dynamic array. Previous data, if any, is
|
|
// deleted.
|
|
//
|
|
// Parameters: numberOfFrames - The number of key frames to be allocated.
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraKeyFramePath::CreateFrames( const int numberOfFrames )
|
|
{
|
|
/// Unload the previous data (if any)
|
|
Unload();
|
|
|
|
/// Allocte <numberOFFrames> CameraKeyFrame objects
|
|
_keyFrameArray = new CameraKeyFrame[ numberOfFrames ];
|
|
if( !_keyFrameArray )
|
|
return( false );
|
|
|
|
/// Set internal dependents
|
|
_numKeyFrames = numberOfFrames;
|
|
return( true );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: ParsePathInfo
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Parses a "Path" entry and all subsequent "Frame" entries for that path.
|
|
// Parsing begins at the '{' following the "Path" keyword (already parsed).
|
|
//
|
|
// Parameters: Script& cameraPathFile - parsing object; keeps track of parse-offset, etc.
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraKeyFramePath::ParsePathInfo( Script& cameraPathFile )
|
|
{
|
|
const char* token;
|
|
|
|
/// Read the opening bracket
|
|
token = cameraPathFile.GetToken( true );
|
|
if( *token != '{' )
|
|
{
|
|
cameraPathFile.error( "CameraKeyFramePath::ParsePathInfo", "Expected '{', found \"%s\"\n", token );
|
|
return( false );
|
|
}
|
|
|
|
/// Read each entry in the Path info block
|
|
token = cameraPathFile.GetToken( true );
|
|
while( *token != '}' )
|
|
{
|
|
if( !stricmp( token, "frameCount" ) )
|
|
{
|
|
/// Read in the number of frames in the path
|
|
_numKeyFrames = cameraPathFile.GetInteger( false );
|
|
assert( _numKeyFrames > 0 );
|
|
}
|
|
else // unknown token
|
|
{
|
|
gi.Printf( "Unexpected token %s in camera path file.\n", token );
|
|
cameraPathFile.error( "CameraKeyFramePath::ParsePathInfo", "Unexpected token %s in camera path file.\n", token );
|
|
return( false );
|
|
}
|
|
token = cameraPathFile.GetToken( true );
|
|
}
|
|
|
|
/// Allocate an array of CameraKeyFrame objects equal in number to what "frameCount" specified
|
|
CreateFrames( _numKeyFrames );
|
|
|
|
/// Loop through each key frame and let it parse itself
|
|
for( int i = 0; i < _numKeyFrames; i ++ )
|
|
{
|
|
/// Tell each frame to parse itself
|
|
CameraKeyFrame& keyFrame = _keyFrameArray[ i ];
|
|
bool success = keyFrame.ParseFrameInfo( i, cameraPathFile, _totalSeconds );
|
|
if( !success )
|
|
return( false );
|
|
}
|
|
|
|
/// Inform the object that it has been successfully loaded and is ready for use
|
|
_isLoaded = true;
|
|
return( true );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: GetClosestFramesForTime
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Sets <before> and <after> pointers to the camera key frames closest in time
|
|
// to <seconds>. Both pointers are guaranteed to always be set, though they
|
|
// may be identical (especially in cases where <seconds> matches a frame exactly,
|
|
// or where <seconds> is out of the time bounds of the path).
|
|
//
|
|
// Parameters: CameraKeyFrame*& before - pointer (by reference) to be set to the closest
|
|
// frame at or before <seconds>
|
|
//
|
|
// CameraKeyFrame*& after - pointer (by reference) to be set to the closest
|
|
// frame at or after <seconds>
|
|
//
|
|
// const float seconds - the time offset, in seconds, from the beginning of the
|
|
// camera path, around which the search for closest frames is centered
|
|
//
|
|
// Returns: void
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
void CameraKeyFramePath::GetClosestFramesForTime( CameraKeyFrame*& before, CameraKeyFrame*& after, const float seconds )
|
|
{
|
|
int i;
|
|
|
|
/// Find the frame closest to - but no greater than - <seconds>
|
|
before = &_keyFrameArray[ 0 ];
|
|
for( i = 0; i < _numKeyFrames; i ++ )
|
|
{
|
|
CameraKeyFrame& frame = _keyFrameArray[ i ];
|
|
if( frame.GetSeconds() > seconds )
|
|
break;
|
|
|
|
before = &frame;
|
|
}
|
|
|
|
/// Find the frame closest to - but no less than - <seconds>
|
|
after = &_keyFrameArray[ _numKeyFrames - 1 ];
|
|
for( i = _numKeyFrames - 1; i >= 0; i -- )
|
|
{
|
|
CameraKeyFrame& frame = _keyFrameArray[ i ];
|
|
if( frame.GetSeconds() < seconds )
|
|
break;
|
|
|
|
after = &frame;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CreateInterpolatedFrameForTime
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Creates a new CameraKeyFrame object based on the best interpolated-approximation
|
|
// of the CameraKeyFramePath when evaluated at <seconds> time.
|
|
//
|
|
// Parameters: const float seconds - time at which to evaluate the camera path
|
|
//
|
|
// Returns: const CameraKeyFrame - a new key frame, created by interpolating (if necessary)
|
|
// between the key frames in the camera path closest to <seconds>.
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
const CameraKeyFrame CameraKeyFramePath::CreateInterpolatedFrameForTime( const float seconds )
|
|
{
|
|
/// Check if <seconds> is out-of-bounds for this camera path
|
|
if( seconds < 0.0f )
|
|
{
|
|
/// Return a copy of the first key frame
|
|
return( _keyFrameArray[ 0 ] );
|
|
}
|
|
else if( seconds > _totalSeconds )
|
|
{
|
|
/// Return a copy of the last key frame
|
|
return( _keyFrameArray[ _numKeyFrames - 1 ] );
|
|
}
|
|
|
|
/// Get the two closest frames in time to <seconds>; one just before and one just after
|
|
CameraKeyFrame* closestFrameBefore = NULL;
|
|
CameraKeyFrame* closestFrameAfter = NULL;
|
|
GetClosestFramesForTime( closestFrameBefore, closestFrameAfter, seconds );
|
|
assert( closestFrameBefore );
|
|
assert( closestFrameAfter );
|
|
|
|
/// Check if both frames are identical; if so, simply return a copy of it / them
|
|
if( closestFrameBefore == closestFrameAfter )
|
|
return( *closestFrameBefore );
|
|
|
|
/// Generate an interpolated frame based on where <seconds> falls between those two frames
|
|
return( CreateInterpolatedFrame( *closestFrameBefore, *closestFrameAfter, seconds ) );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CreateInterpolatedFrame
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Creates a new CameraKeyFrame object based on the best interpolated-approximation
|
|
// of the CameraKeyFramePath when evaluated at <seconds> time. NOTE: This method
|
|
// is called by CreateInterpolatedFrameForTime(), above, and does all the real
|
|
// interpolation work.
|
|
//
|
|
// Parameters: const CameraKeyFrame& before - closest frame shy of <seconds>
|
|
// const CameraKeyFrame& after - closest frame past <seconds>
|
|
// const float seconds - time index used to interpolate between <before> and <after>
|
|
//
|
|
// Returns: const CameraKeyFrame - new, interpolated key frame
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
const CameraKeyFrame CameraKeyFramePath::CreateInterpolatedFrame( const CameraKeyFrame& before, const CameraKeyFrame& after, const float seconds )
|
|
{
|
|
/// Calculate the amount of time between the two reference frames
|
|
const float startTime = before.GetSeconds();
|
|
const float endTime = after.GetSeconds();
|
|
const float timeSpan = endTime - startTime;
|
|
assert( timeSpan >= 0.0f );
|
|
assert( seconds >= startTime );
|
|
assert( seconds <= endTime );
|
|
|
|
/// Calculation the interpolation fraction
|
|
float fraction;
|
|
if( timeSpan )
|
|
{
|
|
fraction = (seconds - startTime) / timeSpan;
|
|
}
|
|
else
|
|
{
|
|
fraction = 0.0f;
|
|
}
|
|
|
|
/// Create a new frame with interpolated values
|
|
CameraKeyFrame lerped;
|
|
lerped.Interpolate( before, after, fraction, true );
|
|
return( lerped );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: GetPathLengthInSeconds
|
|
// Class: CameraKeyFramePath
|
|
//
|
|
// Description: Returns the total length of the camera path, in seconds.
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Returns: float - the total length of the camera path, in seconds.
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
float CameraKeyFramePath::GetPathLengthInSeconds( void )
|
|
{
|
|
return( _totalSeconds );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CameraPath
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
CLASS_DECLARATION( Class, CameraPath, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: CameraPath
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Construct from .KFC file
|
|
//
|
|
// Parameters: fileName Name of the .KFC file to parse on construction of this object.
|
|
//
|
|
// Returns: n/a
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
CameraPath::CameraPath( const str& fileName )
|
|
:
|
|
_fileName( str( "" ) ),
|
|
_isLoaded( false ),
|
|
_keyFramePath( NULL ),
|
|
_yawPlaybackOffsetDegrees( 0.0f ),
|
|
_originPlaybackOffset( Vector( 0.0f, 0.0f, 0.0f ) )
|
|
{
|
|
LoadKeyFramedCameraFile( fileName );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: LoadKeyFramedCameraFile
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Loads a .KFC file and builds a dynamic array of camera key frames.
|
|
// Any previously loaded data in this object is destroyed.
|
|
//
|
|
// Parameters: fileName - Name of the .KFC file to load and parse.
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraPath::LoadKeyFramedCameraFile( const str& fileName )
|
|
{
|
|
Script cameraPathFile;
|
|
const char* token;
|
|
bool success; // generic parsing return-value variable
|
|
str filePathName;
|
|
|
|
/// Unload the previous data (if any)
|
|
Unload();
|
|
|
|
/// Store the filename in the object for duplicate-load later on
|
|
_fileName = fileName;
|
|
|
|
/// Build the new file path name
|
|
filePathName = "cams/";
|
|
filePathName += fileName;
|
|
filePathName += ".kfc";
|
|
|
|
/// Load the file into a buffer (in the Script object)
|
|
cameraPathFile.LoadFile( filePathName.c_str() );
|
|
|
|
/// Parse each token in turn until no more remain
|
|
while( cameraPathFile.TokenAvailable( true ) )
|
|
{
|
|
/// Read the next token-word and take the appropriate action
|
|
token = cameraPathFile.GetToken( true );
|
|
if( !stricmp( token, "Path" ) )
|
|
{
|
|
/// Read in the path info and its subsequent key frame data
|
|
success = ParsePathInfo( cameraPathFile );
|
|
if( !success )
|
|
return( false );
|
|
}
|
|
else // unknown token
|
|
{
|
|
gi.Printf( "Unexpected token %s in camera path file %s.\n", token, _fileName.c_str() );
|
|
cameraPathFile.error( "CameraPath::LoadKeyFramedCameraFile", "Unexpected token %s in camera path file %s.\n", token, _fileName.c_str() );
|
|
return( false );
|
|
}
|
|
}
|
|
|
|
/// Inform the object that it has been successfully loaded and is ready for use
|
|
_isLoaded = true;
|
|
return( true );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: Unload
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Destroys the camera path data and marks the object as dirty (_isLoaded = false).
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Returns: void
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
void CameraPath::Unload( void )
|
|
{
|
|
if( IsLoaded() )
|
|
{
|
|
_isLoaded = false;
|
|
delete _keyFramePath;
|
|
_keyFramePath = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: ParsePathInfo
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Parses the Path #, allocates a new path object, and passes parsing duties onto it.
|
|
//
|
|
// Parameters: Script& cameraPathFile - parsing object
|
|
//
|
|
// Returns: bool - true upon success
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
bool CameraPath::ParsePathInfo( Script& cameraPathFile )
|
|
{
|
|
/// Read the path number
|
|
int pathNumber = cameraPathFile.GetInteger( false );
|
|
assert( pathNumber == 0 ); // FIXME: this is only temporary, until we allow more than one path per .kfc
|
|
|
|
/// Create a new key frame camera path and pass parsing duties on to it
|
|
_keyFramePath = new CameraKeyFramePath;
|
|
bool success = _keyFramePath->ParsePathInfo( cameraPathFile );
|
|
return( success );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: GetInterpolatedFrameForTime
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Returns a newly created temporary object; the resulting camera key frame when
|
|
// the CameraPath is evaluated at <seconds>.
|
|
//
|
|
// Parameters: const float seconds - time index at which to evaluate the camera path
|
|
//
|
|
// Returns: const CameraKeyFrame - key frame created as a result of interpolation / evaluation
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
const CameraKeyFrame CameraPath::GetInterpolatedFrameForTime( const float seconds )
|
|
{
|
|
CameraKeyFrame transformedKeyFrame( _keyFramePath->CreateInterpolatedFrameForTime( seconds ) );
|
|
transformedKeyFrame.TransformToPlaybackOffsets( _yawPlaybackOffsetDegrees, _originPlaybackOffset );
|
|
return( transformedKeyFrame );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: SetPlaybackOffsets
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Tells a CameraPath object what offsets to use when reporting interpolations /
|
|
// evaluations. <yawOffset> is applied first to all positions and orientations;
|
|
// <originOffset> is applied last (to positions only).
|
|
//
|
|
// Parameters: const float yawOffsetDegrees - yaw rotation to apply to all positions & orientations
|
|
// const Vector& originOffset - offset translation applied to all positions, post-rotation
|
|
//
|
|
// Returns: void
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
void CameraPath::SetPlaybackOffsets( const float yawOffsetDegrees, const Vector& originOffset )
|
|
{
|
|
_yawPlaybackOffsetDegrees = yawOffsetDegrees;
|
|
_originPlaybackOffset = originOffset;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
// Name: GetPathLengthInSeconds
|
|
// Class: CameraPath
|
|
//
|
|
// Description: Returns the total length of the camera path, in seconds.
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Returns: float - the total length of the camera path, in seconds
|
|
//
|
|
//-----------------------------------------------------------------------------------------------
|
|
float CameraPath::GetPathLengthInSeconds( void )
|
|
{
|
|
return( _keyFramePath->GetPathLengthInSeconds() );
|
|
}
|
|
|
|
|