thug/Code/Gfx/AnimController.cpp
2016-02-14 08:39:12 +11:00

475 lines
16 KiB
C++

//****************************************************************************
//* MODULE: Gfx
//* FILENAME: AnimChannel.cpp
//* OWNER: Gary Jesdanun
//* CREATION DATE: 12/13/01
//****************************************************************************
// Current state of an animation. There should be no
// references to skeletons or geometry; this is purely
// a time-keeping class).
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <gfx/animcontroller.h>
#include <gel/scripting/script.h>
#include <gel/scripting/checksum.h>
#include <gel/scripting/struct.h>
#include <sys/timer.h>
/*****************************************************************************
** DBG Information **
*****************************************************************************/
namespace Gfx
{
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
float CAnimChannel::get_new_anim_time( void )
{
#ifdef __NOPT_ASSERT__
float old_time = m_currentTime;
#endif
float new_time=0;
float new_hold_time=0;
float new_loop_time=0;
m_animComplete = false;
if ( m_loopingType == LOOPING_WOBBLE )
{
Dbg_MsgAssert( 0, ( "Was not expecting a wobble looping type in this controller" ) );
return 0.0f;
}
if ( m_direction == ANIM_DIR_FORWARDS )
{
new_time = m_currentTime + ( m_animSpeed * Tmr::FrameRatio() );
m_animComplete = new_time > m_endTime;
if (m_startTime == m_endTime)
{
new_loop_time = m_endTime;
}
else
{
new_loop_time = m_startTime + ( new_time - m_endTime );
while ( new_loop_time > m_endTime )
{
// when the FrameRatio() > 1.0f, it's possible that
// we need to subtract more than once, esp. with short anims
new_loop_time = m_startTime + ( new_loop_time - m_endTime );
}
}
new_hold_time = m_endTime;
}
else if ( m_direction == ANIM_DIR_BACKWARDS )
{
new_time = m_currentTime - ( m_animSpeed * Tmr::FrameRatio() );
m_animComplete = new_time < m_startTime;
if (m_startTime == m_endTime)
{
new_loop_time = m_endTime;
}
else
{
new_loop_time = m_endTime + ( new_time - m_startTime );
while ( new_loop_time < m_startTime )
{
// when the FrameRatio() > 1.0f, it's possible that
// we need to subtract more than once, esp. with short anims
new_loop_time = m_endTime + ( new_loop_time - m_startTime );
}
}
new_hold_time = m_startTime;
}
else
{
Dbg_Assert( 0 );
}
if ( m_animComplete )
{
if ( m_loopingType == LOOPING_HOLD )
{
new_time = new_hold_time;
}
else if ( m_loopingType == LOOPING_PINGPONG )
{
m_direction = ( m_direction == ANIM_DIR_FORWARDS ) ? ANIM_DIR_BACKWARDS : ANIM_DIR_FORWARDS;
new_time = new_hold_time;
}
else if ( m_loopingType == LOOPING_CYCLE )
{
new_time = new_loop_time;
}
}
// Ken: This is temporary, to prevent the following assert going off when running a replay.
// Eventually the replays will be fixed to always recreate the correct new_time
if ( new_time < m_startTime )
{
new_time = m_startTime;
}
if ( new_time > m_endTime )
{
new_time = m_endTime;
}
#ifdef __NOPT_ASSERT__
if ( new_time < m_startTime || new_time > m_endTime )
{
Dbg_Message( "old_time = %f", old_time );
Dbg_Message( "new_time = %f", new_time );
Dbg_Message( "new_loop_time = %f", new_loop_time );
Dbg_Message( "new_hold_time = %f", new_hold_time );
Dbg_Message( "m_startTime = %f", m_startTime );
Dbg_Message( "m_endTime = %f", m_endTime );
Dbg_Message( "m_loopingType = %d", m_loopingType );
Dbg_Message( "m_direction = %d", m_direction );
Dbg_Message( "m_animComplete = %d", m_animComplete );
Dbg_Message( "m_animName = %s", Script::FindChecksumName( m_animName ) );
Dbg_Assert( 0 );
}
#endif
return new_time;
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
CAnimChannel::CAnimChannel() : Lst::Node<CAnimChannel>(this)
{
Reset();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CAnimChannel::~CAnimChannel()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::Reset()
{
m_startTime = 0.0f;
m_currentTime = 0.0f;
m_endTime = 0.0f;
m_animSpeed = 0.0f;
m_direction = ANIM_DIR_FORWARDS;
m_loopingType = LOOPING_CYCLE;
m_animComplete = false;
// Ken: Changed this to be a hard wired checksum rather than calling Script::GenerateCRC
// The reason for this is that CAnimChannel::Reset() gets called from
// CSkaterTrackingInfo::Reset() in replay.cpp, which gets called from the CSkaterTrackingInfo
// constructor. There is a static instance of a CSkaterTrackingInfo in replay.cpp, so the
// constructor will get called at some point before main(). Since Script::GenerateCRC accesses
// an array of data, there is a chance that it might get called before the array is initialised,
// since the order of execution is not well defined.
// It probably would be OK, I just want to be safe.
m_animName = 0xf60c9090; // unassigned <-- just giving it a non-zero value, so that
// we can be sure it's getting initialized correctly...
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CAnimChannel::GetCurrentAnim( void )
{
return m_animName;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
float CAnimChannel::GetCurrentAnimTime( void )
{
return m_currentTime;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::GetAnimTimes(float *pStart, float *pCurrent, float *pEnd)
{
Dbg_MsgAssert( pStart, ("NULL pStart") );
Dbg_MsgAssert( pCurrent, ("NULL pCurrent") );
Dbg_MsgAssert( pEnd, ("NULL pEnd") );
*pCurrent = m_currentTime;
if ( m_direction == ANIM_DIR_FORWARDS )
{
*pStart = m_startTime;
*pEnd = m_endTime;
}
else
{
*pStart = m_endTime;
*pEnd = m_startTime;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::AddTime( float incVal )
{
// GJ: a way to fool the animation controller
// into incrementing its time (frame rate
// independent) for the viewer object
float oldAnimSpeed = m_animSpeed;
m_animSpeed = 0.0f;
m_currentTime += incVal;
CAnimChannel::Update();
m_animSpeed = oldAnimSpeed;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::Update()
{
m_currentTime = get_new_anim_time();
}
/******************************************************************/
/* */
/* Returns whether the animation has completed. This is only */
/* valid with "hold on last frame" animations. */
/* */
/******************************************************************/
bool CAnimChannel::IsAnimComplete( void )
{
if ( m_loopingType == LOOPING_HOLD )
{
if ( m_direction == ANIM_DIR_FORWARDS )
{
return ( m_currentTime == m_endTime );
}
else
{
return ( m_currentTime == m_startTime );
}
}
else
{
return false;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CAnimChannel::IsLoopingAnim( void )
{
// Returns whether the current animation will loop forever.
// Used in skater.cpp, to determine whether or not it should
// wait for an animation to finish.
return ( m_loopingType == LOOPING_CYCLE || m_loopingType == LOOPING_PINGPONG );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::SetAnimSpeed( float speed )
{
m_animSpeed = speed / 60.0f;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
float CAnimChannel::GetAnimSpeed( void )
{
return ( m_animSpeed * 60.0f );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::ReverseDirection( void )
{
if ( m_direction == ANIM_DIR_FORWARDS )
{
m_direction = ANIM_DIR_BACKWARDS;
}
else
{
m_direction = ANIM_DIR_FORWARDS;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::SetLoopingType( EAnimLoopingType type )
{
m_loopingType = type;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::PlaySequence( uint32 anim_name, float start_time, float end_time, EAnimLoopingType loop_type, float blend_period, float speed )
{
// Don't reset any more, because this will call the CBlendChannel's virtual
// virtual function, which makes the animation status inactive...
// Reset();
m_startTime = (start_time < end_time) ? start_time : end_time;
m_currentTime = start_time;
m_endTime = (start_time < end_time) ? end_time : start_time;
m_animSpeed = speed / 60.0f;
m_direction = (start_time < end_time) ? ANIM_DIR_FORWARDS : ANIM_DIR_BACKWARDS;
m_loopingType = loop_type;
m_animComplete = false;
m_animName = anim_name;
// Dbg_MsgAssert(m_startTime != m_endTime,("m_startTime == m_endTime (%f) TELL MICK",m_startTime));
// m_wobbleTargetTime = (start_time + end_time) / 2;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CAnimChannel::GetDebugInfo( Script::CStruct* p_info )
{
#ifdef __DEBUG_CODE__
Dbg_MsgAssert( p_info, ( "NULL p_info sent to CAnimChannel::GetDebugInfo" ) );
// put the name first
p_info->AddChecksum( "m_animName", m_animName );
uint32 looping_type_checksum = 0;
switch ( m_loopingType )
{
case 0:
looping_type_checksum = CRCD( 0x3f00df04, "LOOPING_HOLD" );
break;
case 1:
looping_type_checksum = CRCD( 0xfbada576, "LOOPING_CYCLE" );
break;
case 2:
looping_type_checksum = CRCD( 0x792b924b, "LOOPING_PINGPONG" );
break;
case 3:
looping_type_checksum = CRCD( 0x90423ff2, "LOOPING_WOBBLE" );
break;
default:
Dbg_MsgAssert( 0, ( "Unknown looping type found in CAnimChannel::GetDebugInfo. Was the enum changed?" ) );
break;
}
if ( looping_type_checksum )
p_info->AddChecksum( CRCD(0x84b06b3,"m_loopingType"), looping_type_checksum );
switch ( m_direction )
{
case 0:
p_info->AddChecksum( CRCD(0x9f648df4,"m_direction"), CRCD( 0xdf8b2509, "ANIM_DIR_FORWARDS" ) );
break;
case -1:
p_info->AddChecksum( CRCD(0x9f648df4,"m_direction"), CRCD( 0xfdf0c4a4, "ANIM_DIR_BACKWARDS" ) );
break;
default:
Dbg_MsgAssert( 0, ( "Unknown direction found in CAnimChannel::GetDebugInfo. Was the enum changed?" ) );
break;
}
p_info->AddFloat( CRCD(0x8fbac25e,"m_startTime"), m_startTime );
p_info->AddFloat( CRCD(0xb73f0945,"m_currentTime"), m_currentTime );
p_info->AddFloat( CRCD(0xf1cef774,"m_endTime"), m_endTime );
p_info->AddFloat( CRCD(0xaa1e73de,"m_animSpeed"), m_animSpeed );
p_info->AddInteger( CRCD(0x2d574054,"m_animComplete"), m_animComplete );
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
} // namespace Gfx