thug/Code/Sk/Objects/moviedetails.cpp

960 lines
32 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
//****************************************************************************
//* MODULE: Gfx
//* FILENAME: moviedetails.cpp
//* OWNER: Gary Jesdanun
//* CREATION DATE: 06/17/2002
//****************************************************************************
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <sk/objects/moviedetails.h>
#include <gel/components/modelcomponent.h>
#include <gfx/bonedanim.h>
#include <gfx/camera.h>
#include <gfx/nxviewman.h>
#include <gel/assman/assman.h>
#include <gel/objman.h>
#include <gel/scripting/script.h>
#include <gel/scripting/struct.h>
#include <gel/scripting/checksum.h>
#include <gel/scripting/symboltable.h>
#include <sk/modules/skate/skate.h>
#include <gel/object/compositeobject.h>
#include <gfx/skeleton.h>
#include <sk/modules/FrontEnd/FrontEnd.h>
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** DBG Defines **
*****************************************************************************/
namespace Obj
{
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
CMovieDetails::CMovieDetails() : Lst::Node<CMovieDetails>( this )
{
mp_exitParams = NULL;
// defaults to not skippable
m_skippable = false;
m_holdOnLastFrame = false;
m_allowPause = false;
mp_camera = new Gfx::Camera;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CMovieDetails::~CMovieDetails()
{
if ( mp_exitParams )
{
delete mp_exitParams;
}
if ( mp_camera )
{
if (!Nx::CViewportManager::sMarkCameraForDeletion(mp_camera))
{
delete mp_camera;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CMovieDetails::SetParams( Script::CStruct* pParams )
{
Dbg_Assert( pParams );
Dbg_MsgAssert( m_exitScript == 0, ( "exit script was already assigned to %s", Script::FindChecksumName( m_name ) ) );
if ( !mp_exitParams )
{
mp_exitParams = new Script::CStruct;
}
mp_exitParams->Clear();
if ( pParams->GetChecksum( CRCD(0x1a005041,"exitScript"), &m_exitScript, Script::NO_ASSERT ) )
{
Script::CStruct* pSubParams = NULL;
if ( pParams->GetStructure( CRCD(0x894fd988,"exitParams"), &pSubParams, Script::NO_ASSERT ) )
{
mp_exitParams->AppendStructure( pSubParams );
}
}
int skippable = 0;
pParams->GetInteger( CRCD(0x8dde72c0,"skippable"), &skippable, Script::NO_ASSERT );
m_skippable = skippable;
// if we want the movie to continue to hold on the last frame (i.e. don't go on to the next anim)
m_holdOnLastFrame = pParams->ContainsFlag( CRCD(0xeb300c29,"play_hold") );
int allow_pause = 0;
pParams->GetInteger( CRCD(0xb8ca12c5,"allow_pause"), &allow_pause, Script::NO_ASSERT );
m_allowPause = ( allow_pause != 0 );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
Script::CStruct* CMovieDetails::GetParams()
{
Script::CStruct* pReturnParams = new Script::CStruct();
pReturnParams->AddInteger( CRCD(0x8dde72c0,"skippable"), m_skippable );
pReturnParams->AddInteger( CRCD(0xb8ca12c5,"allow_pause"), m_allowPause );
return pReturnParams;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CMovieDetails::Cleanup()
{
// run the exit script
// if ( m_exitScript != 0 )
{
// Dbg_Message( "Running exit script (%s)\n", Script::FindChecksumName(m_exitScript) );
// Script::RunScript( m_exitScript, mp_exitParams, NULL );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CMovieDetails::Abort( bool only_if_skippable )
{
if ( !only_if_skippable )
{
m_aborted = true;
}
if ( m_skippable )
{
m_aborted = true;
}
return m_aborted;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CMovieDetails::SetSkippable( bool skippable )
{
m_skippable = skippable;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CMovieDetails::SetPauseMode( bool pause_mode )
{
m_shouldPause = pause_mode;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CMovieDetails::SetName( uint32 name )
{
m_name = name;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CMovieDetails::GetName()
{
return m_name;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CMovieDetails::CallMemberFunction( uint32 checksum, Script::CStruct* pParams, Script::CScript* pScript )
{
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CObjectAnimDetails::CObjectAnimDetails() : CMovieDetails()
{
// Gfx::CBonedAnimFrameData* mp_frameData;
mp_frameData = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CObjectAnimDetails::~CObjectAnimDetails()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::InitFromStructure( Script::CStruct* pParams )
{
this->SetParams( pParams );
if ( !pParams->ContainsFlag( CRCD(0xee721991,"virtual_cam") ) )
{
Ass::CAssMan* ass_man = Ass::CAssMan::Instance();
Gfx::CBonedAnimFrameData* pData = (Gfx::CBonedAnimFrameData*)ass_man->GetAsset( this->GetName(), false );
if ( !pData )
{
Dbg_Message( "Warning: couldn't find movie with name %s", Script::FindChecksumName( this->GetName() ) );
return false;
}
this->set_frame_data( pData,
pParams->ContainsFlag( CRCD(0x5ea0e211,"loop") ) ? Gfx::LOOPING_CYCLE : Gfx::LOOPING_HOLD,
pParams->ContainsFlag( CRCD(0xf8cfd515,"backwards") ) );
}
else
{
int numFrames = 0;
pParams->GetInteger( CRCD(0x019176c5,"frames"), &numFrames, Script::ASSERT );
this->set_movie_length( numFrames / 60.0f );
}
// by default, pause movie when game is paused
this->SetPauseMode( true );
// now that the new movie is about to start,
// reset all of its custom keys
this->ResetCustomKeys();
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CObjectAnimDetails::Update()
{
update_moving_objects();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CObjectAnimDetails::set_frame_data( Gfx::CBonedAnimFrameData* pFrameData, Gfx::EAnimLoopingType loopingType, bool reverse )
{
Dbg_Assert( pFrameData );
mp_frameData = pFrameData;
if ( !reverse )
{
m_animController.PlaySequence( 0, 0.0f, pFrameData->GetDuration(), loopingType, 0.0f, 1.0f );
}
else
{
// 26Mar03 JCB - When playing backwards, start on the final frame, not beyond the end of the anim.
//
// m_animController.PlaySequence( 0, pFrameData->GetDuration(), 0.0f, loopingType, 0.0f, 1.0f );
m_animController.PlaySequence( 0, pFrameData->GetDuration() - (1.0f/60.0f), 0.0f, loopingType, 0.0f, 1.0f );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CObjectAnimDetails::set_movie_length( float duration )
{
mp_frameData = NULL;
m_animController.PlaySequence( 0, 0.0f, duration, Gfx::LOOPING_HOLD, 0.0f, 1.0f );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::ResetCustomKeys()
{
// eventually, this will go in the decompressed version of the
// frame data, rather than the frame data itself...
if ( mp_frameData )
{
mp_frameData->ResetCustomKeys();
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::process_custom_keys(float startTime, float endTime, bool end_time_inclusive)
{
// This code currently assumes that you're not going to pause the
// camera. If so, then you run the risk of calling these user keys
// more than once...
// TODO: Handle this gracefully!
if ( mp_frameData )
{
Dbg_Assert( mp_camera );
// It depends on the direction also...
mp_frameData->ProcessCustomKeys( startTime, endTime, mp_camera, end_time_inclusive );
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CObjectAnimDetails::update_moving_objects()
{
float oldTime = m_animController.GetCurrentAnimTime();
m_animController.Update();
// Print out some useful information...
//if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
//Dbg_Message( "Moving object anim %s @ %f seconds (%d frames)", Script::FindChecksumName(m_name), m_animController.GetCurrentAnimTime(), (int)(m_animController.GetCurrentAnimTime() * 60.0f) );
}
// process associated keys since last frame
process_custom_keys( oldTime, m_animController.GetCurrentAnimTime(), false );
Mth::Quat* pQuat = new Mth::Quat[mp_frameData->GetNumBones()];
Mth::Vector* pVector = new Mth::Vector[mp_frameData->GetNumBones()];
mp_frameData->GetInterpolatedCameraFrames( pQuat, pVector, m_animController.GetCurrentAnimTime() );
// get the position of each bone
for ( int i = 0; i < mp_frameData->GetNumBones(); i++ )
{
// grab the frame from the animation controller
Dbg_Assert( mp_frameData );
uint32 objName;
objName = mp_frameData->GetBoneName( i );
Obj::CObject* pObject = Obj::ResolveToObject( objName );
Dbg_MsgAssert( pObject, ( "Can't find lookup target %s", Script::FindChecksumName( objName ) ) );
if ( pObject )
{
Obj::CCompositeObject* pCompositeObject = (Obj::CCompositeObject*)pObject;
// update the object's orientation
Mth::Matrix theMatrix;
Mth::Vector nullTrans;
nullTrans.Set(0.0f,0.0f,0.0f,1.0f); // Mick: added separate initialization
Mth::QuatVecToMatrix( pQuat + i, &nullTrans, &theMatrix );
pCompositeObject->SetMatrix( theMatrix );
pCompositeObject->SetDisplayMatrix( theMatrix );
// update the object's position
pCompositeObject->m_pos = pVector[i];
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug") ) )
{
printf( "Object %s @ time %f: ", Script::FindChecksumName(objName), m_animController.GetCurrentAnimTime() );
pCompositeObject->m_pos.PrintContents();
pCompositeObject->m_matrix.PrintContents();
}
// if we want to change the position/rotation,
// then we also need to update the model component
CModelComponent* pModelComponent = GetModelComponentFromObject( pCompositeObject );
if ( pModelComponent )
{
pModelComponent->Update();
}
}
else
{
printf( "object animation: couldn't find object %s\n", Script::FindChecksumName(objName) );
}
}
delete[] pQuat;
delete[] pVector;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::IsComplete()
{
if ( m_aborted )
{
return true;
}
if ( m_holdOnLastFrame )
{
return false;
}
return m_animController.IsAnimComplete();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::IsHeld()
{
/* Added by Ken. Used to determine when camera anims used in */
/* the skate shop front-end have got to their last frame, so that */
/* scripts can trigger things to happen such as the video menu */
/* making the video cassettes pan out to the foreground. */
return ( m_holdOnLastFrame && m_animController.IsAnimComplete() );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CObjectAnimDetails::OverridesCamera()
{
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CSkaterCamDetails::CSkaterCamDetails() : CMovieDetails()
{
mp_frameData = NULL;
// defaults to no target
m_hasTarget = false;
m_targetID = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CSkaterCamDetails::~CSkaterCamDetails()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::InitFromStructure( Script::CStruct* pParams )
{
this->SetParams( pParams );
if ( !pParams->ContainsFlag( CRCD(0xee721991,"virtual_cam") ) )
{
Ass::CAssMan* ass_man = Ass::CAssMan::Instance();
Gfx::CBonedAnimFrameData* pData = (Gfx::CBonedAnimFrameData*)ass_man->GetAsset( this->GetName(), false );
if ( !pData )
{
Dbg_Message( "Warning: couldn't find movie with name %s", Script::FindChecksumName( this->GetName() ) );
return false;
}
this->set_frame_data( pData,
pParams->ContainsFlag( CRCD(0x5ea0e211,"loop") ) ? Gfx::LOOPING_CYCLE : Gfx::LOOPING_HOLD,
pParams->ContainsFlag( CRCD(0xf8cfd515,"backwards") ) );
}
else
{
int numFrames = 0;
pParams->GetInteger( CRCD(0x019176c5,"frames"), &numFrames, Script::ASSERT );
this->set_movie_length( numFrames / 60.0f );
}
// by default, pause movie when game is paused
this->SetPauseMode( true );
// look for target parameters
this->set_target_params( pParams );
// now that the new movie is about to start,
// reset all of its custom keys
this->ResetCustomKeys();
update_camera();
// process initial keys, end time inclusive...
// this to fix an FOV glitch on the first frame
process_custom_keys( m_animController.GetCurrentAnimTime(), m_animController.GetCurrentAnimTime(), true );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::Update()
{
update_camera_time();
update_camera();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::set_target_params( Script::CStruct* pParams )
{
Dbg_Assert( pParams );
m_hasTarget = pParams->GetChecksum( CRCD(0x531e4d28,"targetID"), &m_targetID, Script::NO_ASSERT );
if ( m_hasTarget )
{
// target offset, if any
m_targetOffset.Set(0.0f,0.0f,0.0f);
pParams->GetVector( CRCD(0x906642bf,"targetOffset"), &m_targetOffset, Script::NO_ASSERT );
m_hasTargetOffset = ( m_targetOffset[X] != 0.0f || m_targetOffset[Y] != 0.0f || m_targetOffset[Z] != 0.0f );
// position offset, if any
m_positionOffset.Set(0.0f,0.0f,0.0f);
m_hasPositionOffset = pParams->GetVector( CRCD(0xa00d3d6e,"positionOffset"), &m_positionOffset, Script::NO_ASSERT );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::clear_target_params()
{
m_hasTarget = false;
m_targetID = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::set_frame_data( Gfx::CBonedAnimFrameData* pFrameData, Gfx::EAnimLoopingType loopingType, bool reverse )
{
Dbg_Assert( pFrameData );
mp_frameData = pFrameData;
if ( !reverse )
{
m_animController.PlaySequence( 0, 0.0f, pFrameData->GetDuration(), loopingType, 0.0f, 1.0f );
}
else
{
// 26Mar03 JCB - When playing backwards, start on the final frame, not beyond the end of the anim.
//
// m_animController.PlaySequence( 0, pFrameData->GetDuration(), 0.0f, loopingType, 0.0f, 1.0f );
m_animController.PlaySequence( 0, pFrameData->GetDuration() - (1.0f/60.0f), 0.0f, loopingType, 0.0f, 1.0f );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::set_movie_length( float duration )
{
mp_frameData = NULL;
m_animController.PlaySequence( 0, 0.0f, duration, Gfx::LOOPING_HOLD, 0.0f, 1.0f );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::ResetCustomKeys()
{
// eventually, this will go in the decompressed version of the
// frame data, rather than the frame data itself...
if ( mp_frameData )
{
mp_frameData->ResetCustomKeys();
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::get_current_frame(Mth::Quat* pQuat, Mth::Vector* pTrans)
{
Dbg_Assert( pQuat );
Dbg_Assert( pTrans );
// grab the frame from the animation controller
Dbg_Assert( mp_frameData );
Dbg_Assert( mp_frameData->GetNumBones() == 1 );
mp_frameData->GetInterpolatedCameraFrames( pQuat, pTrans, m_animController.GetCurrentAnimTime() );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::process_custom_keys(float startTime, float endTime, bool end_time_inclusive)
{
// This code currently assumes that you're not going to pause the
// camera. If so, then you run the risk of calling these user keys
// more than once...
// TODO: Handle this gracefully!
if ( mp_frameData )
{
Dbg_Assert( mp_camera );
// It depends on the direction also...
mp_frameData->ProcessCustomKeys( startTime, endTime, mp_camera, end_time_inclusive );
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::update_camera_time()
{
float oldTime = m_animController.GetCurrentAnimTime();
m_animController.Update();
// Not sure if this is still needed for the sound code
// Maybe we can add the functionality automatically to the Gfx::Camera?
mp_camera->StoreOldPos();
// process associated keys since last frame
process_custom_keys( oldTime, m_animController.GetCurrentAnimTime(), false );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterCamDetails::update_camera()
{
Dbg_Assert( mp_camera );
Mth::Vector& camPos = mp_camera->GetPos();
Mth::Matrix& camMatrix = mp_camera->GetMatrix();
Mdl::FrontEnd* pFront = Mdl::FrontEnd::Instance();
for ( int i = 0; i < SIO::vMAX_DEVICES; i++ )
{
if ( pFront->GetInputHandler( i )->m_Input->m_Makes & Inp::Data::mD_X )
{
// abort if skippable
Abort( true );
}
}
if ( mp_frameData )
{
Mth::Quat theQuat;
Mth::Vector theTrans;
get_current_frame( &theQuat, &theTrans );
// update the camera position
camPos = theTrans;
// update the camera orientation
Mth::Vector nullTrans;
nullTrans.Set(0.0f,0.0f,0.0f,1.0f); // Mick: added separate initialization
Mth::QuatVecToMatrix( &theQuat, &nullTrans, &camMatrix );
}
else
{
// clear out the cam matrix to the identity
// if there's no associated animation.
// the assumption is that the following m_hasTarget
// code block will overrride it with the correct data...
camPos = Mth::Vector( 0.0f, 0.0f, 0.0f );
camMatrix.Ident();
// if there's no frame data, then we should
// reset the camera to some default FOV,
// or else it will use the last FOV used
float fov_in_degrees = Script::GetFloat( CRCD(0x99529205, "camera_fov") );
mp_camera->SetHFOV(fov_in_degrees);
}
if ( m_hasTarget )
{
if ( m_targetID != CRCD(0xc588eebc,"world") )
{
// calculate the orientation from the target
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
Obj::CGeneralManager* pObjectManager = skate_mod->GetObjectManager();
Dbg_Assert( pObjectManager );
Obj::CObject* pObject = pObjectManager->GetObjectByID( m_targetID );
Dbg_MsgAssert( pObject, ( "Can't find lookup target %s", Script::FindChecksumName(m_targetID) ) );
if ( pObject )
{
//Dbg_MsgAssert( static_cast<Obj::CCompositeObject*>( pObject ), ( "This function only works on moving objects." ) );
Obj::CCompositeObject* pCompositeObject = (Obj::CCompositeObject*)pObject;
// override it with the moving object's position
Mth::Vector pos = pCompositeObject->GetPos();
// patch for positions that don't have 1.0 in the final column...
// not sure why this would be the case, but it seems to happen
// with the skater... (possibly a result of skater's mp_physics
// disappearing)
pos[W] = 1.0f;
// not properly working yet...
if ( m_hasTargetOffset )
{
Mth::Matrix mat = pCompositeObject->GetMatrix();
mat[Mth::POS] = pos;
mat.TranslateLocal( m_targetOffset );
pos = mat[Mth::POS];
}
if ( m_hasPositionOffset )
{
camPos = pos;
Mth::Matrix mat = pCompositeObject->GetMatrix();
mat[Mth::POS] = pos;
mat.TranslateLocal( m_positionOffset );
camPos = mat[Mth::POS];
}
// set rotation from the camera's position (always up)
Mth::Vector atVec = camPos - pos;
atVec.Normalize();
camMatrix.Ident();
camMatrix[Mth::AT] = atVec;
camMatrix[Mth::RIGHT] = Mth::CrossProduct( camMatrix[Mth::UP], camMatrix[Mth::AT] );
camMatrix[Mth::RIGHT].Normalize();
camMatrix[Mth::UP] = Mth::CrossProduct( camMatrix[Mth::AT], camMatrix[Mth::RIGHT] );
}
}
else
{
// World coordinates are a lot simpler
Mth::Vector pos = m_targetOffset;
camPos = m_positionOffset;
Mth::Vector atVec = camPos - pos;
atVec[W] = 1.0f;
atVec.Normalize();
camMatrix.Ident();
camMatrix[Mth::AT] = atVec;
camMatrix[Mth::RIGHT] = Mth::CrossProduct( camMatrix[Mth::UP], camMatrix[Mth::AT] );
camMatrix[Mth::RIGHT].Normalize();
camMatrix[Mth::UP] = Mth::CrossProduct( camMatrix[Mth::AT], camMatrix[Mth::RIGHT] );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::CallMemberFunction( uint32 checksum, Script::CStruct* pParams, Script::CScript* pScript )
{
switch ( checksum )
{
case 0xa8d5a188: // SetTargetObject
{
Dbg_Message( "*** Calling SetTargetObject" );
set_target_params( pParams );
return true;
}
case 0xd7241a6c: // ClearTargetObject
{
Dbg_Message( "*** Calling ClearTargetObject" );
clear_target_params();
return true;
}
break;
}
return CMovieDetails::CallMemberFunction( checksum, pParams, pScript );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::IsComplete()
{
if ( m_aborted )
{
return true;
}
if ( m_holdOnLastFrame )
{
return false;
}
return m_animController.IsAnimComplete();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::IsHeld()
{
/* Added by Ken. Used to determine when camera anims used in */
/* the skate shop front-end have got to their last frame, so that */
/* scripts can trigger things to happen such as the video menu */
/* making the video cassettes pan out to the foreground. */
return ( m_holdOnLastFrame && m_animController.IsAnimComplete() );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterCamDetails::OverridesCamera()
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
} // namespace Obj