thug/Code/Gfx/CustomAnimKey.cpp

693 lines
22 KiB
C++
Raw Permalink Normal View History

2016-02-13 21:39:12 +00:00
//****************************************************************************
//* MODULE: Gfx
//* FILENAME: CustomAnimKey.cpp
//* OWNER: Gary Jesdanun
//* CREATION DATE: 02/11/2002
//****************************************************************************
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <gfx/customanimkey.h>
#include <gel/scripting/script.h>
#include <gel/scripting/struct.h>
#include <gel/scripting/symboltable.h>
#include <gel/scripting/checksum.h>
#include <gel/scripting/utils.h>
#include <sys/file/filesys.h>
#include <core/math/quat.h>
#include <core/math/vector.h>
#include <gfx/camera.h>
/*****************************************************************************
** DBG Information **
*****************************************************************************/
namespace Gfx
{
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
// all custom keys must have 32-bit data, for the animconv's
// byte-swapping algorithm to work properly
struct SIntermediateCustomAnimKeyHeader
{
uint32 timeStamp;
uint32 keyType;
uint32 size;
};
typedef enum
{
vUNUSED1 = 0,
vCHANGE_FOCAL_LENGTH,
vCHANGE_CAMERA_RT,
vCHANGE_CAMERA_RT_IGNORE,
vRUN_SCRIPT,
vCREATE_OBJECT_FROM_STRUCT,
vKILL_OBJECT_FROM_STRUCT,
vCHANGE_CAMERA_RT_ENDKEY,
};
// class CChangeFOVKey
class CChangeFOVKey : public CCustomAnimKey
{
public:
CChangeFOVKey( int frame, float fov );
public:
virtual bool process_key( Obj::CObject* pObject );
protected:
float m_fov;
};
// class CRunScriptKey
class CRunScriptKey : public CCustomAnimKey
{
public:
CRunScriptKey( int frame, uint32 scriptName );
public:
virtual bool process_key( Obj::CObject* pObject );
protected:
uint32 m_scriptName;
};
// class CChangeCameraRTKey
class CChangeCameraRTKey : public CCustomAnimKey
{
public:
CChangeCameraRTKey( int frame, const Mth::Quat& theQuat, const Mth::Vector& theVector, bool endKey );
public:
virtual bool process_key( Obj::CObject* pObject );
virtual bool WithinRange( float startFrame, float endFrame, bool inclusive );
protected:
Mth::Quat m_rot;
Mth::Vector m_trans;
bool m_endKey;
};
// class CEmptyKey
class CEmptyKey : public CCustomAnimKey
{
public:
CEmptyKey( int frame );
public:
virtual bool process_key( Obj::CObject* pObject );
};
// class CCreateObjectFromStructKey
class CCreateObjectFromStructKey : public CCustomAnimKey
{
public:
CCreateObjectFromStructKey( int frame, uint32 objectStructName );
public:
virtual bool process_key( Obj::CObject* pObject );
protected:
uint32 m_objectStructName;
};
// class CKillObjectFromStructKey
class CKillObjectFromStructKey : public CCustomAnimKey
{
public:
CKillObjectFromStructKey( int frame, uint32 objectStructName );
public:
virtual bool process_key( Obj::CObject* pObject );
protected:
uint32 m_objectStructName;
};
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
CCustomAnimKey::CCustomAnimKey( int frame ) : Lst::Node<CCustomAnimKey>( this ), m_frame( frame )
{
// defaults to inactive
m_active = false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CCustomAnimKey::WithinRange( float startFrame, float endFrame, bool inclusive )
{
if ( inclusive )
{
if ( startFrame < endFrame )
{
// forwards
return ( m_frame >= startFrame && m_frame <= endFrame );
}
else
{
// backwards
return ( m_frame <= startFrame && m_frame >= endFrame );
}
}
else
{
if ( startFrame < endFrame )
{
// forwards
return ( m_frame >= startFrame && m_frame < endFrame );
}
else
{
// backwards
return ( m_frame <= startFrame && m_frame > endFrame );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CCustomAnimKey::SetActive( bool active )
{
m_active = active;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CCustomAnimKey::ProcessKey( Obj::CObject* pObject )
{
if ( !m_active )
{
Dbg_Message( "Key at %d was not active... ignored!", m_frame );
return false;
}
// once it's run, don't run it again...
// (this is in case you pause a movie camera
// on the same frame that it's running a key)
this->SetActive( false );
return process_key( pObject );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CChangeFOVKey::CChangeFOVKey( int frame, float fov ) : CCustomAnimKey( frame ), m_fov( fov )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CChangeFOVKey::process_key( Obj::CObject* pObject )
{
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
Dbg_Message( "Processing Change FOV key (fov = %f, %f) (%d)!", m_fov, Mth::RadToDeg(m_fov), m_frame );
}
Script::CScriptStructure* pParams = new Script::CScriptStructure;
pParams->AddFloat( NONAME, m_fov );
Script::RunScript( "ChangeCameraFov", pParams, pObject );
delete pParams;
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CRunScriptKey::CRunScriptKey( int frame, uint32 scriptName ) : CCustomAnimKey( frame ), m_scriptName( scriptName )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CRunScriptKey::process_key( Obj::CObject* pObject )
{
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
Dbg_Message( "Processing Run Script key (script = %s) @ %d!", Script::FindChecksumName( m_scriptName ), m_frame );
}
Script::RunScript( m_scriptName, NULL, pObject );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CChangeCameraRTKey::CChangeCameraRTKey( int frame, const Mth::Quat& theQuat, const Mth::Vector& theVector, bool isEndKey ) : CCustomAnimKey( frame )
{
// rotate by 90 degrees,
// eventually, we should do this in the build tools
Mth::Quat rotQuat( Mth::Vector(1,0,0), Mth::DegToRad(90.0f) );
m_rot = theQuat * rotQuat;
m_trans[X] = theVector[X];
m_trans[Y] = theVector[Z];
m_trans[Z] = -theVector[Y];
m_trans[W] = 1.0f;
m_endKey = isEndKey;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CChangeCameraRTKey::process_key( Obj::CObject* pObject )
{
// GJ: This key is a kludge to fix the problem with camera
// double-cuts in the cutscene (where we're trying to
// interpolate from one camera to the next, rather
// than just jumping)... the way it works is that
// 2 of these keys need to be inserted right before
// a camera change, which will override the interpolated
// camera values. we need 2 because we're guaranteed
// that the minimum time increment is 1/60th of a second
// so we need to stick these keys in every 1/60th of
// a second between the two cameras. note that this
// won't work properly if we do anim speed changes
// or setslomo, because then the minimum time increment
// is actually less than 1/60th of a second, then it's
// possible that there will be a camera update, without
// an accompanying CChangeCamera key found
// i'd eventually like to look at how WithinRange() works,
// to see if there's a better way to do this.
if ( m_frame == 0 )
{
// GJ KLUDGE: there's an exporter bug that writes out extra camera RT
// keys at the beginning of the cutscene. this skips
// those extra keys
Dbg_Message( "Skipping Change Camera RT key @ %d!", m_frame );
return false;
}
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
Dbg_Message( "Processing Change Camera RT key @ %d!", m_frame );
Dbg_Message( "Quat: %f %f %f %f", m_rot[X], m_rot[Y], m_rot[Z], m_rot[W] );
Dbg_Message( "Trans: %f %f %f %f", m_trans[X], m_trans[Y], m_trans[Z], m_trans[W] );
}
Gfx::Camera* pCamera = (Gfx::Camera*)pObject;
Mth::Vector& camPos = pCamera->GetPos();
Mth::Matrix& camMatrix = pCamera->GetMatrix();
// update the camera position
camPos = m_trans;
// update the camera orientation
Mth::Vector nullTrans;
nullTrans.Set(0.0f,0.0f,0.0f,1.0f); // Mick: added separate initialization
// QuatVecToMatrix destroys the input data, so need to pass in a temp variable
Mth::Quat theQuat = m_rot;
Mth::QuatVecToMatrix( &theQuat, &nullTrans, &camMatrix );
// need this because of our 1-frame range check
this->SetActive( true );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CChangeCameraRTKey::WithinRange( float startFrame, float endFrame, bool inclusive )
{
// good for 1 frame... 1/60th of a frame
if ( inclusive )
{
if ( startFrame < endFrame )
{
// this end key business is used to fix a cutscene glitch
// during camera cuts. the problem is that the keys come
// in sets of 3:
// KEY[-2] KEY[-1] KEY[0]
// old camera old camera new camera
// we basically take the current frame (stored
// in endFrame) and figure out which of the
// three keys should handle it... formerly,
// all three keys handled it, effectively
// causing the last key's camera data to be
// used. to fix the glitch, we need to only
// run the correct key...
if ( m_endKey )
{
if ( endFrame > m_frame )
{
// let it interpolate
return false;
}
}
else
{
if ( m_frame < ( endFrame - 1.0f ) )
{
// there's an end key coming, so let someone else handle it
return false;
}
}
// forwards
return ( m_frame >= ( startFrame - 1.0f ) && m_frame <= endFrame );
}
else
{
// backwards
return ( m_frame <= ( startFrame + 1.0f ) && m_frame >= endFrame );
}
}
else
{
if ( startFrame < endFrame )
{
if ( m_endKey )
{
if ( endFrame > m_frame )
{
// let it interpolate
return false;
}
}
else
{
if ( m_frame < ( endFrame - 1.0f ) )
{
// there's an end key coming, so let someone else handle it
return false;
}
}
// forwards
return ( m_frame >= ( startFrame - 1.0f ) && m_frame < endFrame );
}
else
{
// backwards
return ( m_frame <= ( startFrame + 1.0f ) && m_frame > endFrame );
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CEmptyKey::CEmptyKey( int frame ) : CCustomAnimKey( frame )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CEmptyKey::process_key( Obj::CObject* pObject )
{
// do nothing
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CEventKey::CEventKey( int frame, uint32 eventType, Script::CStruct* pEventParams ) : CCustomAnimKey( frame )
{
m_eventType = eventType;
mp_eventParams = new Script::CStruct;
mp_eventParams->AppendStructure( pEventParams );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CEventKey::~CEventKey()
{
if ( mp_eventParams )
{
delete mp_eventParams;
mp_eventParams = NULL;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CEventKey::process_key( Obj::CObject* pObject )
{
pObject->SelfEvent( m_eventType, mp_eventParams );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CCreateObjectFromStructKey::CCreateObjectFromStructKey( int frame, uint32 objectStructName ) : CCustomAnimKey( frame ), m_objectStructName( objectStructName )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CCreateObjectFromStructKey::process_key( Obj::CObject* pObject )
{
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
Dbg_Message( "Processing Create Object From Struct key (struct = %s) @ %d!", Script::FindChecksumName( m_objectStructName ), m_frame );
}
Script::CStruct* pObjectStruct = Script::GetStructure( m_objectStructName, Script::ASSERT );
if ( pObjectStruct )
{
Script::RunScript( CRCD(0xbdf7f843,"CreateFromStructure"), pObjectStruct );
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CKillObjectFromStructKey::CKillObjectFromStructKey( int frame, uint32 objectStructName ) : CCustomAnimKey( frame ), m_objectStructName( objectStructName )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CKillObjectFromStructKey::process_key( Obj::CObject* pObject )
{
if ( Script::GetInt( CRCD(0x2f510f45,"moviecam_debug"), false ) )
{
Dbg_Message( "Processing Kill Object From Struct key (script = %s) @ %d!", Script::FindChecksumName( m_objectStructName ), m_frame );
}
Script::CStruct* pObjectStruct = Script::GetStructure( m_objectStructName, Script::ASSERT );
if ( pObjectStruct )
{
uint32 objectName;
pObjectStruct->GetChecksum( CRCD(0xa1dc81f9,"name"), &objectName, Script::ASSERT );
Obj::CObject* pObject = (Obj::CObject*)Obj::ResolveToObject( objectName );
pObject->MarkAsDead();
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CCustomAnimKey* ReadCustomAnimKey( uint8** pData )
{
// factory function for generating a custom key...
// TODO: might need to push the heap context
SIntermediateCustomAnimKeyHeader theIntermediateHeader;
memcpy(&theIntermediateHeader, *pData, sizeof(SIntermediateCustomAnimKeyHeader));
*pData += sizeof(SIntermediateCustomAnimKeyHeader);
switch ( theIntermediateHeader.keyType )
{
case vCHANGE_FOCAL_LENGTH:
{
float fov;
memcpy(&fov, *pData, sizeof(float)); // May not be word-aligned in memory
*pData += sizeof(float);
return new CChangeFOVKey( theIntermediateHeader.timeStamp, fov );
}
break;
case vRUN_SCRIPT:
{
uint32 script_name;
memcpy(&script_name, *pData, sizeof(uint32)); // May not be word-aligned in memory
*pData += sizeof(uint32);
return new CRunScriptKey( theIntermediateHeader.timeStamp, script_name );
}
break;
case vCHANGE_CAMERA_RT:
{
Mth::Quat theQuat;
Mth::Vector theVector;
memcpy(&theVector, *pData, sizeof(Mth::Vector));
*pData += sizeof(Mth::Vector);
memcpy(&theQuat, *pData, sizeof(Mth::Quat));
*pData += sizeof(Mth::Quat);
return new CChangeCameraRTKey( theIntermediateHeader.timeStamp, theQuat, theVector, false );
}
break;
case vCHANGE_CAMERA_RT_ENDKEY:
{
Mth::Quat theQuat;
Mth::Vector theVector;
memcpy(&theVector, *pData, sizeof(Mth::Vector));
*pData += sizeof(Mth::Vector);
memcpy(&theQuat, *pData, sizeof(Mth::Quat));
*pData += sizeof(Mth::Quat);
return new CChangeCameraRTKey( theIntermediateHeader.timeStamp, theQuat, theVector, true );
}
break;
case vCHANGE_CAMERA_RT_IGNORE:
{
// GJ: There's a bug in the exporter where
// 2 camera RT keys with different positions
// are listed for the same time... this causes
// a glitch during certain camera transitions.
// To fix, I will replace the second key with one
// that does nothing...
*pData += sizeof(Mth::Vector);
*pData += sizeof(Mth::Quat);
return new CEmptyKey( theIntermediateHeader.timeStamp );
}
break;
case vCREATE_OBJECT_FROM_STRUCT:
{
uint32 object_struct_name;
memcpy(&object_struct_name, *pData, sizeof(uint32)); // May not be word-aligned in memory
*pData += sizeof(uint32);
return new CCreateObjectFromStructKey( theIntermediateHeader.timeStamp, object_struct_name );
}
break;
case vKILL_OBJECT_FROM_STRUCT:
{
uint32 object_struct_name;
memcpy(&object_struct_name, *pData, sizeof(uint32)); // May not be word-aligned in memory
*pData += sizeof(uint32);
return new CKillObjectFromStructKey( theIntermediateHeader.timeStamp, object_struct_name );
}
break;
default:
{
Dbg_Message( "Warning: Ignoring custom anim key (type %08x is currently unsupported).", theIntermediateHeader.keyType );
// just skip past the size
Dbg_Assert( theIntermediateHeader.size - sizeof(SIntermediateCustomAnimKeyHeader) < 512 );
*pData += theIntermediateHeader.size;
Dbg_Assert(!((uint) *pData & 0x3));
return NULL;
}
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
} // namespace Gfx