thug/Code/Gfx/BonedAnim.cpp

2648 lines
78 KiB
C++
Raw Permalink Normal View History

2016-02-13 21:39:12 +00:00
//****************************************************************************
//* MODULE: Gfx
//* FILENAME: bonedanim.cpp
//* OWNER: Gary Jesdanun
//* CREATION DATE: 11/14/2001
//****************************************************************************
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <gfx/bonedanim.h>
#include <gfx/bonedanimtypes.h>
#include <gfx/nxquickanim.h>
#include <sys/file/AsyncFilesys.h>
#include <sys/file/filesys.h>
#include <sys/mem/memman.h>
#include <gel/object.h>
#include <gel/scripting/script.h>
#include <gel/scripting/checksum.h>
#include <sys/config/config.h>
#include <core/string/stringutils.h>
#include <sys/file/pip.h>
#ifdef __PLAT_NGC__
#include <dolphin.h>
#include "sys/ngc/p_dma.h"
#include "sys\ngc\p_aram.h"
#endif // __PLAT_NGC__
/*****************************************************************************
** DBG Information **
*****************************************************************************/
#ifdef __PLAT_NGC__
#define __ARAM__
#endif
#ifdef __PLAT_NGC__
#define _16(a) (((a>>8)&0x00ff)|((a<<8)&0xff00))
#define _32(a) (((a>>24)&0x000000ff)|((a>>8)&0x0000ff00)|((a<<8)&0x00ff0000)|((a<<24)&0xff000000))
#else
#define _16(a) a
#define _32(a) a
#endif // __PLAT_NGC__
namespace Gfx
{
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
// In order to compress the data, we convert the animation quat into
// a unit quat and then discard the W value during export-time/load-time.
// Given the X, Y, Z values, we can rebuild the W value at run-time.
// The code uses the following tolerance to when comparing the rebuilt W value
// to the original value. I chose the number pretty arbitrarily, based
// on the existing (THPS3) skater and pedestrian animations.
//(0.0005 radians ~= 0.028 degrees)
const float nxUNITQUAT_TOLERANCE_RADIANS = 0.0005f;
/*****************************************************************************
** Private Types **
*****************************************************************************/
// The following structures are only needed until new data
// is exported in the correct format
struct SBonedAnimFileHeader
{
uint32 version;
uint32 flags;
float duration;
};
struct SPlatformFileHeader
{
uint32 numBones;
uint32 numQKeys;
uint32 numTKeys;
uint32 numCustomAnimKeys;
};
struct SStandardAnimFramePointers
{
unsigned char numQKeys;
unsigned char numTKeys;
};
struct SHiResAnimFramePointers
{
short numQKeys;
short numTKeys;
};
//#define nxBONEDANIMFLAGS_UNUSED (1<<31)
#define nxBONEDANIMFLAGS_INTERMEDIATE (1<<30)
#define nxBONEDANIMFLAGS_UNCOMPRESSED (1<<29)
#define nxBONEDANIMFLAGS_PLATFORM (1<<28)
#define nxBONEDANIMFLAGS_CAMERADATA (1<<27)
#define nxBONEDANIMFLAGS_COMPRESSEDTIME (1<<26)
#define nxBONEDANIMFLAGS_PREROTATEDROOT (1<<25)
#define nxBONEDANIMFLAGS_OBJECTANIMDATA (1<<24)
#define nxBONEDANIMFLAGS_USECOMPRESSTABLE (1<<23)
#define nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS (1<<22)
#define nxBONEDANIMFLAGS_CUSTOMKEYSAT60FPS (1<<21)
#define nxBONEDANIMFLAGS_CUTSCENEDATA (1<<20)
#define nxBONEDANIMFLAGS_PARTIALANIM (1<<19)
// to be phased out...
#define nxBONEDANIMFLAGS_OLDPARTIALANIM (1<<18)
/*****************************************************************************
** Private Data **
*****************************************************************************/
#ifdef __ARAM__
#define ARAM_CACHE_SIZE (64*1024)
#define MAX_BONE_COUNT 128
static char qqq[ARAM_CACHE_SIZE] ATTRIBUTE_ALIGN(32);
static uint16 framecount[MAX_BONE_COUNT*2] ATTRIBUTE_ALIGN(32);
//static uint32 partial[8] ATTRIBUTE_ALIGN(32);
volatile uint8 framecount_active = 0;
static int framecount_size = 0;
ARQRequest framecount_request;
#endif
/*****************************************************************************
** Public Data **
*****************************************************************************/
// compress tables take up 4K,
// which are a waste on Xbox and GC
// (should PLAT_NGPS it once it's working)
struct CBonedAnimCompressEntry
{
short x48;
short y48;
short z48;
short n8;
};
CBonedAnimCompressEntry sQTable[256];
CBonedAnimCompressEntry sTTable[256];
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
bool init_48_table( void* pStream, CBonedAnimCompressEntry* pEntry )
{
for ( int i = 0; i < 256; i++ )
{
if ( !File::Read( (int*)&pEntry->x48, sizeof(short), 1, pStream ) )
{
return false;
}
if ( !File::Read( (int*)&pEntry->y48, sizeof(short), 1, pStream ) )
{
return false;
}
if ( !File::Read( (int*)&pEntry->z48, sizeof(short), 1, pStream ) )
{
return false;
}
if ( !File::Read( (int*)&pEntry->n8, sizeof(short), 1, pStream ) )
{
return false;
}
pEntry->x48 = _16( pEntry->x48 );
pEntry->y48 = _16( pEntry->y48 );
pEntry->z48 = _16( pEntry->z48 );
pEntry->n8 = _16( pEntry->n8 );
pEntry++;
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#ifdef __ARAM__
//static volatile bool dmaComplete;
static void arqCallback( u32 pointerToARQRequest )
{
// ARQRequest * p_arq = (ARQRequest *)pointerToARQRequest;
// if ( p_arq->owner == 0x55555555 )
// {
framecount_active = 0;
// }
}
void dma_count( uint32 p_source_base, int size )
{
// DMA the count info.
size = ( ( size + 31 ) & ~31 );
DCFlushRange ( framecount, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
p_source_base, // Source.
(uint32)framecount, // Dest.
size, // Length.
arqCallback ); // Callback
}
//void dma_partial( uint32 p_source_base )
//{
// while ( framecount_active );
// // DMA the count info.
// DCFlushRange ( partial, 32 );
// framecount_size = 32;
// framecount_active = 1;
// ARQPostRequest ( &framecount_request,
// 0x55555555, // Owner.
// ARQ_TYPE_ARAM_TO_MRAM, // Type.
// ARQ_PRIORITY_HIGH, // Priority.
// p_source_base, // Source.
// (uint32)partial, // Dest.
// 32, // Length.
// arqCallback ); // Callback
//}
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
bool InitQ48Table( const char* pFileName, bool assertOnFail )
{
bool success = false;
// open the file as a stream
void* pStream = File::Open( pFileName, "rb" );
// make sure the file is valid
if ( !pStream )
{
Dbg_MsgAssert( !assertOnFail, ("Load of %s failed - file not found?", pFileName) );
goto exit;
}
success = init_48_table( pStream, &sQTable[0] );
exit:
Dbg_MsgAssert( success, ("Parse of %s failed", pFileName) );
File::Close( pStream );
return success;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool InitT48Table( const char* pFileName, bool assertOnFail )
{
bool success = false;
// open the file as a stream
void* pStream = File::Open( pFileName, "rb" );
// make sure the file is valid
if ( !pStream )
{
Dbg_MsgAssert( assertOnFail, ("Load of %s failed - file not found?", pFileName) );
goto exit;
}
success = init_48_table( pStream, &sTTable[0] );
//Dbg_Assert( 0 );
exit:
Dbg_MsgAssert( success, ("Parse of %s failed", pFileName) );
File::Close( pStream );
return success;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline float timeDown(short theSource)
{
return (float)theSource;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline short timeUp(float theSource)
{
short retVal = (short)((theSource * 60.0f) + 0.5f);
return retVal;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline short transUp(float theSource, float scaleFactor)
{
return (short)(theSource * scaleFactor);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline float transDown(short theSource, float scaleFactor)
{
return (float)(theSource / scaleFactor);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline short quatUp(float theSource)
{
return (short)(theSource * 16384.0f);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline float quatDown(short theSource)
{
return (float)(theSource / 16384.0f);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void get_rotation_from_key( CAnimQKey* p_in, Mth::Quat* pQuat, bool isHiRes )
{
if ( isHiRes )
{
(*pQuat)[X] = ((CHiResAnimQKey*)p_in)->qx;
(*pQuat)[Y] = ((CHiResAnimQKey*)p_in)->qy;
(*pQuat)[Z] = ((CHiResAnimQKey*)p_in)->qz;
// (*pQuat)[W] = ((CHiResAnimQKey*)p_in)->qw;
}
else
{
(*pQuat)[X] = quatDown( ((CStandardAnimQKey*)p_in)->qx );
(*pQuat)[Y] = quatDown( ((CStandardAnimQKey*)p_in)->qy );
(*pQuat)[Z] = quatDown( ((CStandardAnimQKey*)p_in)->qz );
// (*pQuat)[W] = quatDown( ((CStandardAnimQKey*)p_in)->qw );
}
float qx = (*pQuat)[X];
float qy = (*pQuat)[Y];
float qz = (*pQuat)[Z];
// Dave note: added 09/12/02 - a simple check to ensure we don't try to take the square root of a negative
// number, which will hose Nan-sensitive platforms later on...
float sum = 1.0f - qx * qx - qy * qy - qz * qz;
(*pQuat)[W] = sqrtf(( sum >= 0.0f ) ? sum : 0.0f );
if ( p_in->signBit )
{
(*pQuat)[W] = -(*pQuat)[W];
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void set_key_from_rotation( CAnimQKey* p_in, float x, float y, float z, float w, bool isHiRes )
{
if ( isHiRes )
{
((CHiResAnimQKey*)p_in)->qx = x;
((CHiResAnimQKey*)p_in)->qy = y;
((CHiResAnimQKey*)p_in)->qz = z;
// ((CHiResAnimQKey*)p_in)->qw = w;
((CHiResAnimQKey*)p_in)->signBit = ( w < 0.0f ) ? 1 : 0;
}
else
{
((CStandardAnimQKey*)p_in)->qx = quatUp( x );
((CStandardAnimQKey*)p_in)->qy = quatUp( y );
((CStandardAnimQKey*)p_in)->qz = quatUp( z );
// ((CStandardAnimQKey*)p_in)->qw = quatUp( w );
((CStandardAnimQKey*)p_in)->signBit = ( w < 0.0f ) ? 1 : 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void get_translation_from_key( CAnimTKey* p_in, Mth::Vector* pVector, bool isHiRes )
{
if ( isHiRes )
{
(*pVector)[X] = ((CHiResAnimTKey*)p_in)->tx;
(*pVector)[Y] = ((CHiResAnimTKey*)p_in)->ty;
(*pVector)[Z] = ((CHiResAnimTKey*)p_in)->tz;
(*pVector)[W] = 1.0f;
}
else
{
(*pVector)[X] = transDown( ((CStandardAnimTKey*)p_in)->tx, 32.0f );
(*pVector)[Y] = transDown( ((CStandardAnimTKey*)p_in)->ty, 32.0f );
(*pVector)[Z] = transDown( ((CStandardAnimTKey*)p_in)->tz, 32.0f );
(*pVector)[W] = 1.0f;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void get_rotation_from_standard_key( CStandardAnimQKey* p_in, Mth::Quat* pQuat )
{
if ( p_in->qx == 0 && p_in->qy == 0 && p_in->qz == 0 )
{
// Optimization: this handles the identity rotation, which is so common that it's not
// worth doing a square root...
pQuat->SetVector( 0.0f, 0.0f, 0.0f );
pQuat->SetScalar( 1.0f );
return;
}
float qx = quatDown( p_in->qx );
float qy = quatDown( p_in->qy );
float qz = quatDown( p_in->qz );
// Dave note: added 09/12/02 - a simple check to ensure we don't try
// to take the square root of a negative number, which will hose
// Nan-sensitive platforms later on...
float sum = 1.0f - qx * qx - qy * qy - qz * qz;
// This assert was firing off in one of the cutscenes...
// probably worth looking into later...
// Dbg_Assert( sum >= 0.0f );
if ( sum < 0.0f )
{
sum = 0.0f;
}
(*pQuat)[X] = qx;
(*pQuat)[Y] = qy;
(*pQuat)[Z] = qz;
(*pQuat)[W] = ( p_in->signBit ) ? -sqrtf( sum ) : sqrtf( sum );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void get_translation_from_standard_key( CStandardAnimTKey* p_in, Mth::Vector* pVector )
{
(*pVector)[X] = transDown( p_in->tx, 32.0f );
(*pVector)[Y] = transDown( p_in->ty, 32.0f );
(*pVector)[Z] = transDown( p_in->tz, 32.0f );
(*pVector)[W] = 1.0f;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void set_key_from_translation( CAnimTKey* p_in, float x, float y, float z, bool isHiRes )
{
if ( isHiRes )
{
((CHiResAnimTKey*)p_in)->tx = x;
((CHiResAnimTKey*)p_in)->ty = y;
((CHiResAnimTKey*)p_in)->tz = z;
}
else
{
((CStandardAnimTKey*)p_in)->tx = transUp( x, 32.0f );
((CStandardAnimTKey*)p_in)->ty = transUp( y, 32.0f );
((CStandardAnimTKey*)p_in)->tz = transUp( z, 32.0f );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void interpolate_q_frame(Mth::Quat* p_out, CAnimQKey* p_in1, CAnimQKey* p_in2, float alpha, bool isHiRes)
{
if ( alpha == 0.0f )
{
// don't need to slerp, because it's the start time
get_rotation_from_key( p_in1, p_out, isHiRes );
return;
}
if ( alpha == 1.0f )
{
// don't need to slerp, because it's the end time
get_rotation_from_key( p_in2, p_out, isHiRes );
return;
}
// INTERPOLATE Q-COMPONENT
Mth::Quat qIn1;
Mth::Quat qIn2;
get_rotation_from_key( p_in1, &qIn1, isHiRes );
get_rotation_from_key( p_in2, &qIn2, isHiRes );
// Faster slerp, stolen from game developer magazine.
*p_out = Mth::FastSlerp( qIn1, qIn2, alpha );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void interpolate_t_frame(Mth::Vector* p_out, CAnimTKey* p_in1, CAnimTKey* p_in2, float alpha, bool isHiRes)
{
if ( alpha == 0.0f )
{
// don't need to lerp, because it's the start time
get_translation_from_key( p_in1, p_out, isHiRes );
return;
}
if ( alpha == 1.0f )
{
// don't need to slerp, because it's the end time
get_translation_from_key( p_in2, p_out, isHiRes );
return;
}
// INTERPOLATE T-COMPONENT
Mth::Vector tIn1;
Mth::Vector tIn2;
get_translation_from_key( p_in1, &tIn1, isHiRes );
get_translation_from_key( p_in2, &tIn2, isHiRes );
/* Linearly interpolate positions */
*p_out = Mth::Lerp( tIn1, tIn2, alpha );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void interpolate_standard_q_frame(Mth::Quat* p_out, CStandardAnimQKey* p_in1, CStandardAnimQKey* p_in2, float alpha)
{
if ( alpha == 0.0f )
{
// don't need to slerp, because it's the start time
get_rotation_from_standard_key( p_in1, p_out );
return;
}
if ( alpha == 1.0f )
{
// don't need to slerp, because it's the end time
get_rotation_from_standard_key( p_in2, p_out );
return;
}
// INTERPOLATE Q-COMPONENT
Mth::Quat qIn1;
Mth::Quat qIn2;
get_rotation_from_standard_key( p_in1, &qIn1 );
get_rotation_from_standard_key( p_in2, &qIn2 );
// Faster slerp, stolen from game developer magazine.
*p_out = Mth::FastSlerp( qIn1, qIn2, alpha );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline void interpolate_standard_t_frame(Mth::Vector* p_out, CStandardAnimTKey* p_in1, CStandardAnimTKey* p_in2, float alpha)
{
if ( alpha == 0.0f )
{
// don't need to lerp, because it's the start time
get_translation_from_standard_key( p_in1, p_out );
return;
}
if ( alpha == 1.0f )
{
// don't need to slerp, because it's the end time
get_translation_from_standard_key( p_in2, p_out );
return;
}
// INTERPOLATE T-COMPONENT
Mth::Vector tIn1;
Mth::Vector tIn2;
get_translation_from_standard_key( p_in1, &tIn1 );
get_translation_from_standard_key( p_in2, &tIn2 );
/* Linearly interpolate positions */
*p_out = Mth::Lerp( tIn1, tIn2, alpha );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
// eventually, this will go in the plat-specific version of CBonedAnimFrameData
bool CBonedAnimFrameData::plat_dma_to_aram( int qbytes, int tbytes, uint32 flags )
{
// GameCube: DMA to ARAM.
#ifdef __ARAM__
if ( qbytes && tbytes )
{
uint32 address;
uint size;
// uint32 header[8];
// // Want this to happen even if asserts turned off.
// if ( qbytes > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many q keys (%d)!!!\n", qbytes );
// while (1);
// }
//
// if ( tbytes > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many t keys (%d)!!!\n", tbytes );
// while (1);
// }
//
// if ( m_numBones > MAX_BONE_COUNT )
// {
// OSReport( "Too many bones (%d)!!!\n", m_numBones );
// while (1);
// }
// // DMA partial animation data.
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// address = NsARAM::alloc( 32 );
// NsDMA::toARAM( address, mp_partialAnimData, 32 );
// mp_partialAnimData = (uint32*)address;
// }
// DMA per-bone frame count data.
size = m_numBones * sizeof(uint16) * 2;
memcpy( qqq, mp_perBoneQFrameSize, size );
int part_size = 0;
int frame_size = size;
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
part_size = ( 1 + (( *mp_partialAnimData - 1 )/ 32) + 1 ) * sizeof( uint32 );
memcpy( &qqq[size], mp_partialAnimData, part_size );
size += part_size;
}
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, qqq, size );
mp_perBoneQFrameSize = (uint16*)address;
mp_perBoneTFrameSize = (uint16*)address;
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
mp_partialAnimData = (uint32*)( address + frame_size );
}
// size = m_numBones * sizeof(uint16) * 2;
// size = ( ( size + 31 ) & ~31 );
// address = NsARAM::alloc( size );
// NsDMA::toARAM( address, mp_perBoneQFrameSize, size );
//
// mp_perBoneQFrameSize = (uint16*)address;
// mp_perBoneTFrameSize = (uint16*)address;
// DMA Q frames to ARAM, delete RAM version & assign ARAM pointer.
size = qbytes/* + 32*/;
size = ( ( size + 31 ) & ~31 );
// header[0] = size;
address = NsARAM::alloc( size );
// NsDMA::toARAM( address, header, 32 );
NsDMA::toARAM( address/*+32*/, mp_qFrames, size );
// delete mp_qFrames;
mp_qFrames = (char*)address;
// DMA T frames to ARAM, delete RAM version & assign ARAM pointer.
size = tbytes/* + 32*/;
size = ( ( size + 31 ) & ~31 );
// header[0] = size;
address = NsARAM::alloc( size );
// NsDMA::toARAM( address, header, 32 );
NsDMA::toARAM( address/*+32*/, mp_tFrames, size );
// delete mp_tFrames;
mp_tFrames = (char*)address;
// hijack this pointer as it won't be used.
mp_boneNames = (uint32*)( ( qbytes << 16 ) | tbytes );
}
else
{
if ( is_hires() )
{
uint32 address;
uint size;
// // Want this to happen even if asserts turned off.
// if ( ( m_num_qFrames * sizeof( CHiResAnimQKey ) ) > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many q keys (%d)!!!\n", m_num_qFrames );
// while (1);
// }
//
// if ( ( m_num_tFrames * sizeof( CHiResAnimTKey ) ) > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many t keys (%d)!!!\n", m_num_tFrames );
// while (1);
// }
//
// // DMA partial animation data.
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// uint32 * pData = mp_partialAnimData;
// int numBones = *pData;
//
// int numMasks = (( numBones - 1 )/ 32) + 1;
// size = sizeof( int ) + ( numMasks * sizeof( uint32 ) );
//
// header[0] = size;
// address = NsARAM::alloc( size );
// NsDMA::toARAM( address, header, 32 );
// NsDMA::toARAM( address+32, mp_partialAnimData, size );
// mp_partialAnimData = (char*)address;
// }
mp_partialAnimData = NULL;
// DMA per-bone frame count data.
void * ptr;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
size = ( m_numBones * sizeof(uint32) );
ptr = mp_boneNames;
}
else
{
size = 0;
ptr = mp_perBoneFrames;
}
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
size += ( m_numBones * sizeof(SHiResAnimFramePointers) );
}
else
{
size += ( m_numBones * sizeof(SStandardAnimFramePointers) );
}
if ( size > ( MAX_BONE_COUNT * 2 * sizeof(uint16) ) )
{
OSReport( "Too many bones (%d)!!!\n", m_numBones );
while (1);
}
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, ptr, size );
mp_perBoneFrames = (uint16*)address;
mp_perBoneQFrameSize = (uint16*)address; // So that it can be deallocated.
// DMA Q frames to ARAM, delete RAM version & assign ARAM pointer.
// Dbg_MsgAssert( m_num_qFrames <= (ARAM_CACHE_SIZE), ( "Too many hires Q keys (%d) - maximum is %d", m_num_qFrames, (ARAM_CACHE_SIZE) ) );
size = sizeof( CHiResAnimQKey ) * m_num_qFrames;
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, mp_qFrames, size );
// delete mp_qFrames;
mp_qFrames = (char*)address;
// DMA T frames to ARAM, delete RAM version & assign ARAM pointer.
// Dbg_MsgAssert( m_num_tFrames <= (ARAM_CACHE_SIZE), ( "Too many hires T keys (%d) - maximum is %d", m_num_tFrames, (ARAM_CACHE_SIZE) ) );
size = sizeof( CHiResAnimTKey ) * m_num_tFrames;
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, mp_tFrames, size );
// delete mp_tFrames;
mp_tFrames = (char*)address;
}
else
{
uint32 address;
uint size;
// // Want this to happen even if asserts turned off.
// if ( ( m_num_qFrames * sizeof( CStandardAnimQKey ) ) > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many q keys (%d)!!!\n", m_num_qFrames );
// while (1);
// }
//
// if ( ( m_num_tFrames * sizeof( CStandardAnimTKey ) ) > (ARAM_CACHE_SIZE) )
// {
// OSReport( "Too many t keys (%d)!!!\n", m_num_tFrames );
// while (1);
// }
//
// // DMA partial animation data.
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// uint32 * pData = mp_partialAnimData;
// int numBones = *pData;
//
// int numMasks = (( numBones - 1 )/ 32) + 1;
// size = sizeof( int ) + ( numMasks * sizeof( uint32 ) );
//
// header[0] = size;
// address = NsARAM::alloc( size );
// NsDMA::toARAM( address, header, 32 );
// NsDMA::toARAM( address+32, mp_partialAnimData, size );
// mp_partialAnimData = (char*)address;
// }
mp_partialAnimData = NULL;
// DMA per-bone frame count data.
void * ptr;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
size = ( m_numBones * sizeof(uint32) );
ptr = mp_boneNames;
}
else
{
size = 0;
ptr = mp_perBoneFrames;
}
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
size += ( m_numBones * sizeof(SHiResAnimFramePointers) );
}
else
{
size += ( m_numBones * sizeof(SStandardAnimFramePointers) );
}
if ( size > ( MAX_BONE_COUNT * 2 * sizeof(uint16) ) )
{
OSReport( "Too many bones (%d)!!!\n", m_numBones );
while (1);
}
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, ptr, size );
mp_perBoneFrames = (uint16*)address;
mp_perBoneQFrameSize = (uint16*)address; // So that it can be deallocated.
// DMA Q frames to ARAM, delete RAM version & assign ARAM pointer.
// Dbg_MsgAssert( m_num_qFrames <= (short)MAX_STANDARD_Q, ( "Too many standard Q keys (%d) - maximum is %d", m_num_qFrames, MAX_STANDARD_Q ) );
size = sizeof( CStandardAnimQKey ) * m_num_qFrames;
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, mp_qFrames, size );
// delete mp_qFrames;
mp_qFrames = (char*)address;
// DMA T frames to ARAM, delete RAM version & assign ARAM pointer.
// Dbg_MsgAssert( m_num_tFrames <= (short)MAX_STANDARD_T, ( "Too many standard T keys (%d) - maximum is %d", m_num_tFrames, MAX_STANDARD_T ) );
size = sizeof( CStandardAnimTKey ) * m_num_tFrames;
size = ( ( size + 31 ) & ~31 );
address = NsARAM::alloc( size );
NsDMA::toARAM( address, mp_tFrames, size );
// delete mp_tFrames;
mp_tFrames = (char*)address;
}
}
#endif // __ARAM__
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::plat_read_compressed_stream(uint8* pData, bool delete_buffer)
{
Dbg_Assert( pData );
SPlatformFileHeader *pThePlatformHeader = (SPlatformFileHeader *) pData;
pData += sizeof(SPlatformFileHeader);
m_numBones = pThePlatformHeader->numBones;
m_num_qFrames = pThePlatformHeader->numQKeys;
m_num_tFrames = pThePlatformHeader->numTKeys;
uint32 qAllocSize = *((uint32*)pData);
pData += sizeof(uint32);
uint32 tAllocSize = *((uint32*)pData);
pData += sizeof(uint32);
mp_perBoneQFrameSize = (uint16*)pData;
pData += ( m_numBones * sizeof(uint16) );
mp_perBoneTFrameSize = (uint16*)pData;
pData += ( m_numBones * sizeof(uint16) );
// long-align
if ( (uint32)pData & 0x3 )
{
pData += ( 4 - ((uint32)pData & 0x3) );
}
// first read in object anim bone names, if any
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
Dbg_MsgAssert( 0, ( "Wasn't expecting object anims to be compressed" ) );
mp_boneNames = NULL;
}
else
{
mp_boneNames = NULL;
}
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
Dbg_Assert(!((uint32)pData & 0x3));
mp_partialAnimData = (uint32*)pData;
// skip original number of bones
int numBones = *((uint32*)pData);
pData += sizeof( int );
int numMasks = (( numBones - 1 )/ 32) + 1;
pData += ( numMasks * sizeof( uint32 ) );
}
// long-align
if ( (uint32)pData & 0x3 )
{
pData += ( 4 - ((uint32)pData & 0x3) );
}
if ( is_hires() )
{
Dbg_MsgAssert( !is_hires(), ( "Hi res format not supported for compressed anims" ) );
}
else
{
mp_qFrames = (char*)pData;
pData += qAllocSize;
mp_tFrames = (char*)pData;
pData += tAllocSize;
}
Dbg_Assert( mp_perBoneFrames == NULL );
Dbg_Assert( mp_qFrames );
Dbg_Assert( mp_tFrames );
// dma to aram here...
plat_dma_to_aram( qAllocSize, tAllocSize );
// GJ: be able to PIP the custom keys in as well
// long-align
if ( (uint32)pData & 0x3 )
{
pData += ( 4 - ((uint32)pData & 0x3) );
}
// create an array of pointers to the custom keys
if ( !pThePlatformHeader->numCustomAnimKeys )
{
mpp_customAnimKeyList = NULL;
}
else
{
mpp_customAnimKeyList = (CCustomAnimKey **)(Mem::Malloc(pThePlatformHeader->numCustomAnimKeys*sizeof(CCustomAnimKey *)));
// read custom keys
for ( uint32 i = 0; i < pThePlatformHeader->numCustomAnimKeys; i++ )
{
CCustomAnimKey* pKey = ReadCustomAnimKey( &pData );
if ( !pKey )
{
Dbg_Message( "Failed while reading custom data" );
return false;
}
mpp_customAnimKeyList[i] = pKey;
}
}
m_num_customKeys = pThePlatformHeader->numCustomAnimKeys;
#ifdef __ARAM__
if ( delete_buffer )
{
delete mp_fileBuffer;
}
mp_fileBuffer = NULL;
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::plat_read_stream(uint8* pData, bool delete_buffer)
{
Dbg_Assert( pData );
SPlatformFileHeader* pThePlatformHeader = (SPlatformFileHeader*)pData;
pData += sizeof(SPlatformFileHeader);
Dbg_Assert(!((uint) pData & 0x3));
m_numBones = pThePlatformHeader->numBones;
m_num_qFrames = pThePlatformHeader->numQKeys;
m_num_tFrames = pThePlatformHeader->numTKeys;
Dbg_Assert( !mp_perBoneFrames );
Dbg_Assert( !mp_qFrames );
Dbg_Assert( !mp_tFrames );
// first read in object anim bone names, if any
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
Dbg_Assert(!((uint) pData & 0x3));
mp_boneNames = (uint32*)pData;
pData += ( m_numBones * sizeof(uint32) );
}
else
{
mp_boneNames = NULL;
}
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
Dbg_Assert(!((uint32)pData & 0x3));
mp_partialAnimData = (uint32*)pData;
// skip original number of bones
int numBones = *((uint32*)pData);
pData += sizeof( int );
int numMasks = (( numBones - 1 )/ 32) + 1;
pData += ( numMasks * sizeof( uint32 ) );
}
// now, read in the per-bone frames of the correct size
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
mp_perBoneFrames = pData;
pData += ( m_numBones * sizeof(SHiResAnimFramePointers) );
}
else
{
mp_perBoneFrames = pData;
pData += ( m_numBones * sizeof(SStandardAnimFramePointers) );
}
// long-align
if ( (uint32)pData & 0x3 )
{
pData += ( 4 - ((uint32)pData & 0x3) );
}
// count to make sure the number of keys per bone didn't overflow
int runningQCount = 0;
int runningTCount = 0;
for ( int i = 0; i < m_numBones; i++ )
{
runningQCount += get_num_qkeys( mp_perBoneFrames, i );
runningTCount += get_num_tkeys( mp_perBoneFrames, i );
}
Dbg_MsgAssert( runningQCount == m_num_qFrames, ( "Wrong number of qframes in %x %d %d", m_fileNameCRC, runningQCount, m_num_qFrames ) );
Dbg_MsgAssert( runningTCount == m_num_tFrames, ( "Wrong number of tframes in %x %d %d", m_fileNameCRC, runningTCount, m_num_tFrames ) );
if ( is_hires() )
{
Dbg_Assert(!((uint) pData & 0x3));
mp_qFrames = (char*)pData;
pData += ( m_num_qFrames * sizeof(CHiResAnimQKey) );
Dbg_Assert(!((uint) pData & 0x3));
mp_tFrames = (char*)pData;
pData += ( m_num_tFrames * sizeof(CHiResAnimTKey) );
}
else
{
Dbg_Assert(!((uint) pData & 0x3));
mp_qFrames = (char*)pData;
pData += ( m_num_qFrames * sizeof(CStandardAnimQKey) );
Dbg_Assert(!((uint) pData & 0x3));
mp_tFrames = (char*)pData;
pData += ( m_num_tFrames * sizeof(CStandardAnimTKey) );
}
Dbg_Assert( mp_perBoneFrames );
Dbg_Assert( mp_qFrames );
Dbg_Assert( mp_tFrames );
// dma to aram here...
plat_dma_to_aram( 0, 0, m_flags );
// GJ: be able to PIP the custom keys in as well
// long-align
if ( (uint32)pData & 0x3 )
{
pData += ( 4 - ((uint32)pData & 0x3) );
}
// create an array of pointers to the custom keys
if ( !pThePlatformHeader->numCustomAnimKeys )
{
mpp_customAnimKeyList = NULL;
}
else
{
mpp_customAnimKeyList = (CCustomAnimKey **)(Mem::Malloc(pThePlatformHeader->numCustomAnimKeys*sizeof(CCustomAnimKey *)));
// read custom keys
for ( uint32 i = 0; i < pThePlatformHeader->numCustomAnimKeys; i++ )
{
CCustomAnimKey* pKey = ReadCustomAnimKey( &pData );
if ( !pKey )
{
Dbg_Message( "Failed while reading custom data" );
return false;
}
mpp_customAnimKeyList[i] = pKey;
}
}
m_num_customKeys = pThePlatformHeader->numCustomAnimKeys;
#ifdef __ARAM__
if ( delete_buffer )
{
delete mp_fileBuffer;
}
mp_fileBuffer = NULL;
#endif
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CBonedAnimFrameData::get_num_qkeys( void * p_frame_data, int boneIndex ) const
{
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
SHiResAnimFramePointers* pFramePointers = (SHiResAnimFramePointers*)p_frame_data;
pFramePointers += boneIndex;
return pFramePointers->numQKeys;
}
else
{
SStandardAnimFramePointers* pFramePointers = (SStandardAnimFramePointers*)p_frame_data;
pFramePointers += boneIndex;
return pFramePointers->numQKeys;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CBonedAnimFrameData::get_num_tkeys( void * p_frame_data, int boneIndex ) const
{
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
SHiResAnimFramePointers* pFramePointers = (SHiResAnimFramePointers*)p_frame_data;
pFramePointers += boneIndex;
return pFramePointers->numTKeys;
}
else
{
SStandardAnimFramePointers* pFramePointers = (SStandardAnimFramePointers*)p_frame_data;
pFramePointers += boneIndex;
return pFramePointers->numTKeys;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::is_hires() const
{
return ( m_flags & nxBONEDANIMFLAGS_CAMERADATA ) || ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA );
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
CBonedAnimFrameData::CBonedAnimFrameData()
{
m_duration = 0.0f;
m_numBones = 0;
mp_fileBuffer = NULL;
mp_fileHandle = NULL;
m_dataLoaded = false;
mp_qFrames = NULL;
mp_tFrames = NULL;
mp_perBoneFrames = NULL;
mp_boneNames = NULL;
mp_perBoneQFrameSize = NULL;
mp_perBoneTFrameSize = NULL;
m_printDebugInfo = false;
m_num_customKeys = 0;
mpp_customAnimKeyList = NULL;
m_fileNameCRC = 0;
m_pipped = false;
mp_partialAnimData = NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CBonedAnimFrameData::~CBonedAnimFrameData()
{
for (int i=0;i<m_num_customKeys;i++)
{
delete mpp_customAnimKeyList[i];
}
if ( mpp_customAnimKeyList )
{
Mem::Free( mpp_customAnimKeyList );
}
if ( m_pipped )
{
Pip::Unload( m_fileNameCRC );
}
else
{
if (mp_fileBuffer)
{
Mem::Free(mp_fileBuffer);
}
}
if (mp_fileHandle)
{
Dbg_MsgAssert(m_dataLoaded, ("Can't delete CBonedAnimFrameData while it is still being loaded"));
File::CAsyncFileLoader::sClose( mp_fileHandle );
}
#ifdef __ARAM__
// This relies on all level-specific anims being deallocated (a reasonable dependency).
// Animations can be deleted in any order, the lowest address is the base address for the next level.
NsARAM::free( (uint32)mp_perBoneQFrameSize );
NsARAM::free( (uint32)mp_qFrames );
NsARAM::free( (uint32)mp_tFrames );
// if ( ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM ) && mp_partialAnimData )
// {
// NsARAM::free( (uint32)mp_partialAnimData );
// }
#else
#endif // __ARAM__
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::Load(uint32* pData, int file_size, bool assertOnFail)
{
// TODO: We should read in the entire file into memory first, because
// using streams is slow.
Dbg_Assert( !m_dataLoaded );
m_fileNameCRC = 0;
Dbg_MsgAssert( pData, ( "No data pointer specified" ) );
Dbg_MsgAssert(file_size, ("Anim file size is 0"));
Dbg_Assert(!mp_fileBuffer);
#ifdef __ARAM__
mp_fileBuffer = pData;
return PostLoad(assertOnFail, file_size, false);
#else
// Now that we're pipping it, we don't have to force this on the top-down heap
// Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
mp_fileBuffer = (void *) Mem::Malloc( file_size );
// Mem::Manager::sHandle().PopContext();
// copy the data into the temporary buffer
memcpy( mp_fileBuffer, pData, file_size );
// printf( "Loading data: %08x %08x %08x %d\n", *pData, mp_fileBuffer, pData, file_size );
return PostLoad(assertOnFail, file_size);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::Load(const char* p_fileName, bool assertOnFail, bool async, bool use_pip)
{
// TODO: We should read in the entire file into memory first, because
// using streams is slow.
Dbg_Assert( p_fileName );
Dbg_Assert( !m_dataLoaded );
char test[256];
strcpy( test, p_fileName );
Str::LowerCase( test );
m_fileNameCRC = Crc::GenerateCRCFromString( test );
int file_size = 0;
char filename[256];
strcpy( filename, p_fileName );
// Turn off async for platforms that don't support it
if (!File::CAsyncFileLoader::sAsyncSupported())
{
async = false;
}
if ( async )
{
Dbg_MsgAssert( !use_pip, ( "Pip-files do not work with async-loaded anims" ) );
// Pre-load
Dbg_Assert(!mp_fileHandle);
mp_fileHandle = File::CAsyncFileLoader::sOpen( p_fileName, !async );
// make sure the file is valid
if ( !mp_fileHandle )
{
Dbg_MsgAssert( assertOnFail, ("Load of %s failed - file not found?", p_fileName) );
return false;
}
file_size = mp_fileHandle->GetFileSize();
Dbg_MsgAssert(file_size, ("Anim file size is 0"));
Dbg_Assert(!mp_fileBuffer);
// Now that we're pipping it, we don't have to force this on the top-down heap
// Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
mp_fileBuffer = (void *) Mem::Malloc( file_size );
// Mem::Manager::sHandle().PopContext();
// Set the callback
mp_fileHandle->SetCallback(async_callback, (unsigned int) this, (unsigned int) assertOnFail);
// read the file in
mp_fileHandle->Read( mp_fileBuffer, 1, file_size );
//Dbg_Message("Started read of %x", this);
//mp_fileHandle->WaitForIO();
//Dbg_Message("Done waiting for %x", this);
// Should be the callback
return true; //PostLoad(assertOnFail, file_size);
}
else
{
int file_size = 0;
if ( use_pip )
{
mp_fileBuffer = Pip::Load( p_fileName );
file_size = Pip::GetFileSize( p_fileName );
Dbg_MsgAssert(file_size, ("Anim file size is 0"));
m_pipped = true;
}
else
{
// open the file as a stream
void* pStream = File::Open( p_fileName,"rb" );
// make sure the file is valid
if ( !pStream )
{
Dbg_MsgAssert( assertOnFail, ("Load of %s failed - file not found?", p_fileName) );
return false;
}
file_size = File::GetFileSize(pStream);
Dbg_MsgAssert(file_size, ("Anim file size is 0"));
Dbg_Assert(!mp_fileBuffer);
// Now that we're pipping it, we don't have to force this on the top-down heap
// Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
mp_fileBuffer = (void *) Mem::Malloc( file_size );
// Mem::Manager::sHandle().PopContext();
// read the file in
if ( !File::Read( mp_fileBuffer, 1, file_size, pStream ) )
{
Mem::Free(mp_fileBuffer);
mp_fileBuffer = NULL;
File::Close( pStream );
Dbg_MsgAssert( assertOnFail, ("Load of %s failed - bad format?", p_fileName) );
return false;
}
File::Close(pStream);
}
return PostLoad(assertOnFail, file_size);
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CBonedAnimFrameData::async_callback(File::CAsyncFileHandle *, File::EAsyncFunctionType function,
int result, unsigned int arg0, unsigned int arg1)
{
//Dbg_Message("Got callback from %x", arg0);
if (function == File::FUNC_READ)
{
CBonedAnimFrameData *p_data = (CBonedAnimFrameData *) arg0;
bool assert = (bool) arg1;
p_data->PostLoad(assert, result);
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::PostLoad(bool assertOnFail, int file_size, bool delete_buffer)
{
bool success = false;
//Dbg_Message("PostLoad of %x", this);
// Handle end of async, if that was used
if (mp_fileHandle)
{
#if 0
if (mp_fileHandle->WaitForIO() != file_size)
{
Mem::Free(mp_fileBuffer);
mp_fileBuffer = NULL;
File::CAsyncFileLoader::sClose( mp_fileHandle );
mp_fileHandle = NULL;
Dbg_MsgAssert( assertOnFail, ("PostLoad of anim file failed - bad format?") );
return false;
}
#endif
File::CAsyncFileLoader::sClose( mp_fileHandle );
mp_fileHandle = NULL;
}
uint8 *pFileData = (uint8 *) mp_fileBuffer;
// read in header information
SBonedAnimFileHeader* pTheHeader = (SBonedAnimFileHeader*)pFileData;
pFileData += sizeof(SBonedAnimFileHeader);
// store header information
m_duration = pTheHeader->duration;
m_flags = pTheHeader->flags;
// trying to phase out the old partial anim format here...
Dbg_MsgAssert( ( m_flags & nxBONEDANIMFLAGS_OLDPARTIALANIM ) == 0, ( "No longer supporting old partial anim format" ) );
// the anim converter should automatically do this,
// so that we don't have to do it at runtime...
Dbg_MsgAssert( pTheHeader->flags & nxBONEDANIMFLAGS_COMPRESSEDTIME, ( "Expected the anim times to be in frames" ) );
Dbg_MsgAssert( pTheHeader->flags & nxBONEDANIMFLAGS_PREROTATEDROOT, ( "Expected the root bones to be prerotated" ) );
// some debugging information
// Dbg_Message( "Loading animation %s", p_fileName );
// Dbg_Message( "Duration = %f", m_duration );
// Dbg_Message( "Flags = %08x", theHeader.flags );
// read the stream differently based on whether it's compressed...
if ( pTheHeader->flags & nxBONEDANIMFLAGS_PLATFORM )
{
Dbg_Assert( (pTheHeader->flags & nxBONEDANIMFLAGS_USECOMPRESSTABLE) == 0 );
success = this->plat_read_stream( pFileData, delete_buffer );
}
else if ( pTheHeader->flags & nxBONEDANIMFLAGS_USECOMPRESSTABLE )
{
Dbg_Assert( (pTheHeader->flags & nxBONEDANIMFLAGS_PLATFORM) == 0 );
success = this->plat_read_compressed_stream( pFileData, delete_buffer );
}
else
{
Dbg_MsgAssert( 0, ("Unrecognized file format (flags = %08x)...", pTheHeader->flags) );
}
// handle failure
Dbg_MsgAssert( success || !assertOnFail, ("PostLoad of anim file failed - bad format?") );
if ( !m_pipped )
{
// Done with temp buffer (since it's pipped, don't delete the file buffer)
// Mem::Free(mp_fileBuffer);
// mp_fileBuffer = NULL;
}
m_dataLoaded = success;
return success;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::IsValidTime( float time )
{
return ( time >= 0.0f && time < m_duration );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
inline float get_alpha( float timeStamp1, float timeStamp2, float time )
{
Dbg_MsgAssert(timeStamp1 <= time && timeStamp2 >= time, ( "%f should be within [%f %f]", time, timeStamp1, timeStamp2 ));
return (( time - timeStamp1 ) / ( timeStamp2 - timeStamp1 ));
}
// THE FOLLOWING 2 FUNCTIONS SHOULD BE REFACTORED?
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::GetInterpolatedCameraFrames(Mth::Quat* pRotations, Mth::Vector* pTranslations, float time, Nx::CQuickAnim* pQuickAnim )
{
Dbg_Assert( pRotations );
Dbg_Assert( pTranslations );
Dbg_Assert( is_hires() );
float qAlpha = 0.0f;
float tAlpha = 0.0f;
// DMA the animation data here.
#ifdef __ARAM__
int size;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
size = ( m_numBones * sizeof(uint32) );
}
else
{
size = 0;
}
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
size += ( m_numBones * sizeof(SHiResAnimFramePointers) );
}
else
{
size += ( m_numBones * sizeof(SStandardAnimFramePointers) );
}
dma_count( (uint32)mp_perBoneFrames, size );
while ( framecount_active );
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// dma_partial( (uint32)mp_partialAnimData, ( m_numBones * sizeof( uint16 ) * 2 ) );
// }
// while ( framecount_active );
// NsDMA::toMRAM( qqq, (uint32)mp_qFrames, m_num_qFrames * sizeof( CHiResAnimQKey ) );
// NsDMA::toMRAM( ttt, (uint32)mp_tFrames, m_num_tFrames * sizeof( CHiResAnimTKey ) );
// while( framecount_active );
#endif // __ARAM__
// find the nearest 2 keyframes
float qTimeStamp = time * 60.0f;
float tTimeStamp = time * 60.0f;
CHiResAnimQKey* pStartQFrame = NULL;
CHiResAnimQKey* pEndQFrame = NULL;
CHiResAnimTKey* pStartTFrame = NULL;
CHiResAnimTKey* pEndTFrame = NULL;
CHiResAnimQKey* pCurrentQFrame = NULL;
CHiResAnimTKey* pCurrentTFrame = NULL;
#ifdef __ARAM__
// pStartQFrame = p_hqqq;
// pEndQFrame = p_hqqq;
//
// pStartTFrame = p_httt;
// pEndTFrame = p_httt;
//
// pCurrentQFrame = p_hqqq;
// pCurrentTFrame = p_httt;
uint32 anim_q_offset = (uint32)mp_qFrames;
uint32 anim_t_offset = (uint32)mp_tFrames;
void * p_bone_frames;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
p_bone_frames = &framecount[m_numBones*2];
}
else
{
p_bone_frames = framecount;
}
#else
pStartQFrame = (CHiResAnimQKey*)mp_qFrames;
pEndQFrame = pStartQFrame;
pCurrentQFrame = pStartQFrame;
pStartTFrame = (CHiResAnimTKey*)mp_tFrames;
pEndTFrame = pStartTFrame;
pCurrentTFrame = pStartTFrame;
void * p_bone_frames = mp_perBoneFrames;
#endif // __aram__
for ( int i = 0; i < m_numBones; i++ )
{
int numQKeys = get_num_qkeys( p_bone_frames, i );
int numTKeys = get_num_tkeys( p_bone_frames, i );
#ifdef __ARAM__
int q_off = 0;
{
// DMA this q track.
int aligned_off = ( anim_q_offset & ~31 );
int size = ( ( ( sizeof( CHiResAnimQKey ) * numQKeys ) - ( aligned_off - anim_q_offset ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
while ( framecount_active );
q_off = anim_q_offset - aligned_off;
pStartQFrame = (CHiResAnimQKey*)&qqq[q_off];
pEndQFrame = (CHiResAnimQKey*)&qqq[q_off];
pCurrentQFrame = (CHiResAnimQKey*)&qqq[q_off];
}
#endif // __ARAM__
for ( int j = 0; j < numQKeys; j++ )
{
if ( j == (numQKeys-1) )
{
// last frame
pStartQFrame = pCurrentQFrame + j;
pEndQFrame = pCurrentQFrame + j;
qAlpha = 0.0f;
break;
}
else if ( qTimeStamp >= timeDown(pCurrentQFrame[j].timestamp)
&& qTimeStamp <= timeDown(pCurrentQFrame[j+1].timestamp) )
{
pStartQFrame = pCurrentQFrame + j;
pEndQFrame = pCurrentQFrame + j + 1;
qAlpha = get_alpha( timeDown(pStartQFrame->timestamp), timeDown(pEndQFrame->timestamp), qTimeStamp );
break;
}
}
interpolate_q_frame( pRotations,
pStartQFrame,
pEndQFrame,
qAlpha,
is_hires() );
#ifdef __ARAM__
int t_off = 0;
{
// DMA this t track.
int aligned_off = ( anim_t_offset & ~31 );
int size = ( ( ( sizeof( CHiResAnimTKey ) * numTKeys ) - ( aligned_off - anim_t_offset ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
while ( framecount_active );
t_off = anim_t_offset - aligned_off;
pStartTFrame = (CHiResAnimTKey*)&qqq[t_off];
pEndTFrame = (CHiResAnimTKey*)&qqq[t_off];
pCurrentTFrame = (CHiResAnimTKey*)&qqq[t_off];
}
#endif // __ARAM__
for ( int j = 0; j < numTKeys; j++ )
{
if ( j == (numTKeys-1) )
{
// last frame
pStartTFrame = pCurrentTFrame + j;
pEndTFrame = pCurrentTFrame + j;
tAlpha = 0.0f;
break;
}
else if ( tTimeStamp >= timeDown(pCurrentTFrame[j].timestamp)
&& tTimeStamp <= timeDown(pCurrentTFrame[j+1].timestamp) )
{
pStartTFrame = pCurrentTFrame + j;
pEndTFrame = pCurrentTFrame + j + 1;
tAlpha = get_alpha( timeDown(pStartTFrame->timestamp), timeDown(pEndTFrame->timestamp), tTimeStamp );
break;
}
}
// theStartFrame and theEndFrame should contain the
// two closest keyframes here. now interpolate between them
// TODO: we might be able to cache some of this data...
interpolate_t_frame( pTranslations,
pStartTFrame,
pEndTFrame,
tAlpha,
is_hires() );
#if 0
if ( m_printDebugInfo )
{
// for debug info, if necessary
}
#endif
#ifdef __ARAM__
anim_q_offset += ( sizeof( CHiResAnimQKey ) * numQKeys );
anim_t_offset += ( sizeof( CHiResAnimTKey ) * numTKeys );
#else
pCurrentQFrame += numQKeys;
pCurrentTFrame += numTKeys;
#endif // __ARAM__
pRotations++;
pTranslations++;
}
return true;
}
#ifdef __ARAM__
inline int get_compressed_q_frame( char* pData, CStandardAnimQKey* pReturnData )
#else
inline char * get_compressed_q_frame( char* pData, CStandardAnimQKey* pReturnData )
#endif // __ARAM__
{
unsigned char* p_data = (unsigned char*)pData;
short data = (short)(( p_data[1]<<8 ) | p_data[0] );
pReturnData->timestamp = data & 0x3fff;
pReturnData->signBit = data & 0x8000 ? 1 : 0;
// skip the timestamp
p_data += sizeof( short );
if ( data & 0x4000 )
{
if ( !(data & 0x3800) )
{
unsigned char d = *p_data;
// a char* defaults to a signed char*,
// which means you'll try
// to access outside the array
// boundaries... brutal!
//Dbg_Assert( *p_data == d );
CBonedAnimCompressEntry* pEntry = &sQTable[d];
pReturnData->qx = pEntry->x48;
pReturnData->qy = pEntry->y48;
pReturnData->qz = pEntry->z48;
p_data += sizeof( char );
// remove the bits
pReturnData->timestamp &= 0x07ff;
}
else
{
if ( data & 0x2000 )
{
pReturnData->qx = p_data[0];
p_data += sizeof( char );
}
else
{
pReturnData->qx = (p_data[1]<<8) | p_data[0];
p_data += sizeof( short );
}
if ( data & 0x1000 )
{
pReturnData->qy = p_data[0];
p_data += sizeof( char );
}
else
{
pReturnData->qy = (p_data[1]<<8) | p_data[0];
p_data += sizeof( short );
}
if ( data & 0x0800 )
{
pReturnData->qz = p_data[0];
p_data += sizeof( char );
}
else
{
pReturnData->qz = (p_data[1]<<8) | p_data[0];
p_data += sizeof( short );
}
// remove the bits
pReturnData->timestamp &= 0x07ff;
}
}
else
{
// no compression
pReturnData->qx = (p_data[1]<<8) | p_data[0];
pReturnData->qy = (p_data[3]<<8) | p_data[2];
pReturnData->qz = (p_data[5]<<8) | p_data[4];
p_data += 6;
}
#ifdef __ARAM__
return (int)p_data - (int)pData;
#else
return (char*)p_data;
#endif // __ARAM__
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#ifdef __ARAM__
inline int get_compressed_t_frame( char* pData, CStandardAnimTKey* pReturnData )
#else
inline char * get_compressed_t_frame( char* pData, CStandardAnimTKey* pReturnData )
#endif // __ARAM__
{
unsigned char* p_data = (unsigned char*)pData;
bool useLookupTable = false;
unsigned char flags = *p_data;
p_data += sizeof( char );
if ( flags & 0x80 )
{
useLookupTable = true;
}
if ( flags & 0x40 )
{
// expand the timestamp
pReturnData->timestamp = (unsigned short)(flags & 0x3f);
}
else
{
// read another short
pReturnData->timestamp = (unsigned short)(p_data[1]<<8) | p_data[0];
p_data += sizeof( short );
}
if ( useLookupTable )
{
unsigned char d = *p_data;
// defaults to signed char,
// which means you'll try
// to access outside the array
// boundaries... brutal!
//Dbg_Assert( *p_data == d );
CBonedAnimCompressEntry* pEntry = &sTTable[d];
pReturnData->tx = pEntry->x48;
pReturnData->ty = pEntry->y48;
pReturnData->tz = pEntry->z48;
p_data += sizeof( char );
}
else
{
// no compression
pReturnData->tx = (p_data[1]<<8) | p_data[0];
pReturnData->ty = (p_data[3]<<8) | p_data[2];
pReturnData->tz = (p_data[5]<<8) | p_data[4];
p_data += 6;
}
#ifdef __ARAM__
return (int)p_data - (int)pData;
#else
return (char*)p_data;
#endif // __ARAM__
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::GetCompressedInterpolatedFrames(Mth::Quat* pRotations, Mth::Vector* pTranslations, float time, Nx::CQuickAnim* pQuickAnim )
{
Dbg_Assert( pRotations );
Dbg_Assert( pTranslations );
Dbg_Assert( !is_hires() );
CStandardAnimQKey theStartQFrame;
CStandardAnimQKey theEndQFrame;
CStandardAnimQKey* pStartQFrame = &theStartQFrame;
CStandardAnimQKey* pEndQFrame = &theEndQFrame;
CStandardAnimTKey theStartTFrame;
CStandardAnimTKey theEndTFrame;
CStandardAnimTKey* pStartTFrame = &theStartTFrame;
CStandardAnimTKey* pEndTFrame = &theEndTFrame;
#ifdef __ARAM__
char* pCurrentQFrame = mp_qFrames;//&mp_qFrames[32];
char* pCurrentTFrame = mp_tFrames;//&mp_tFrames[32];
// Pre-dma framecount sizes.
dma_count( (uint32)mp_perBoneQFrameSize, ( m_numBones * sizeof( uint16 ) * 2 ) + 16 ); // +16 should cover partial mask data.
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// while ( framecount_active );
// dma_partial( (uint32)mp_partialAnimData );
// }
// uint32 * partial = (uint32 *)&framecount[( (uint32)mp_partialAnimData - (uint32)mp_perBoneQFrameSize ) * 2];
uint32 * partial = (uint32 *)&framecount[( (uint32)mp_partialAnimData - (uint32)mp_perBoneQFrameSize ) / 2];
// Pre-DMA all data.
// uint32 q_lines = ((uint32)mp_boneNames) >> 16;
// uint32 t_lines = ((uint32)mp_boneNames) & 0xffff;
// q_lines = ( ( q_lines + ( ARAM_CACHE_LINE_SIZE - 1 ) ) / ARAM_CACHE_LINE_SIZE );
// t_lines = ( ( t_lines + ( ARAM_CACHE_LINE_SIZE - 1 ) ) / ARAM_CACHE_LINE_SIZE );
// for ( uint32 lp = 0; lp < q_lines; lp++ ) dma_q_entry( ((uint32)mp_qFrames), lp );
// for ( uint32 lp = 0; lp < t_lines; lp++ ) dma_t_entry( ((uint32)mp_tFrames), lp );
uint16* pQSizes = &framecount[0];
uint16* pTSizes = &framecount[m_numBones];
// Make sure framecount sizes have been DMA'd.
while ( framecount_active );
#else
Dbg_Assert( mp_qFrames );
Dbg_Assert( mp_tFrames );
char* pCurrentQFrame = (char*)mp_qFrames;
char* pCurrentTFrame = (char*)mp_tFrames;
uint16* pQSizes = &mp_perBoneQFrameSize[0];
uint16* pTSizes = &mp_perBoneTFrameSize[0];
#endif // __aram__
// find the nearest 2 keyframes
float qTimeStamp = time * 60.0f;
float tTimeStamp = time * 60.0f;
// Precalculate the skip index mask for speed.
uint32 skip_index_mask = ( pQuickAnim && pQuickAnim->m_quickAnimPointers.valid ) ? ( 1 << pQuickAnim->m_quickAnimPointers.skipIndex ) : 0;
for ( int i = 0; i < m_numBones; i++ )
{
// See if the QuickAnim data indicates that this bone may be skipped.
bool skip_this_bone = ( skip_index_mask ) ? (( pQuickAnim->m_quickAnimPointers.pSkipList[i] & skip_index_mask ) > 0 ) : false;
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
#ifdef __ARAM__
uint32* pBoneMask = ( partial + 1 ) + ( i / 32 );
#else
uint32* pBoneMask = ( mp_partialAnimData + 1 ) + ( i / 32 );
#endif // __ARAM__
skip_this_bone = ( ( (*pBoneMask) & ( 1 << (i%32) ) ) == 0 );
// skip_this_bone = ( ( (*pBoneMask) & ( (1<<31) >> (i%32) ) ) == 0 );
}
if( !skip_this_bone )
{
float qAlpha = 0.0f;
float tAlpha = 0.0f;
char* pNextQFrame = pCurrentQFrame;
char* pNextQBone = pCurrentQFrame + *pQSizes;
char* pNextTFrame = pCurrentTFrame;
char* pNextTBone = pCurrentTFrame + *pTSizes;
if ( pQuickAnim && pQuickAnim->m_quickAnimPointers.valid )
{
pNextQFrame = pQuickAnim->m_quickAnimPointers.pQuickQKey[i];
pNextTFrame = pQuickAnim->m_quickAnimPointers.pQuickTKey[i];
}
#ifdef __ARAM__
int q_off = 0;
{
// DMA this q track.
uint aligned_off = ( (int)pNextQFrame & ~31 );
uint size = ( ( *pQSizes - ( aligned_off - (int)pCurrentQFrame ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
q_off = (int)pNextQFrame - aligned_off;
}
#endif // __ARAM__
while ( 1 )
{
if ( pQuickAnim )
{
pQuickAnim->m_quickAnimPointers.pQuickQKey[i] = (char*)pNextQFrame;
}
# ifdef __ARAM__
while ( framecount_active );
# endif // __ARAM__
#ifdef __ARAM__
int bytes = get_compressed_q_frame( &qqq[q_off], pStartQFrame );
q_off += bytes;
pNextQFrame = &pNextQFrame[bytes];
#else
pNextQFrame = get_compressed_q_frame( pNextQFrame, pStartQFrame );
#endif // __ARAM__
if ( pNextQFrame >= pNextQBone )
{
// last frame
*pEndQFrame = *pStartQFrame;
qAlpha = 0.0f;
break;
}
#ifdef __ARAM__
get_compressed_q_frame( &qqq[q_off], pEndQFrame );
#else
get_compressed_q_frame( pNextQFrame, pEndQFrame );
#endif // __ARAM__
if ( qTimeStamp >= timeDown(pStartQFrame->timestamp) && qTimeStamp <= timeDown(pEndQFrame->timestamp) )
{
qAlpha = get_alpha( timeDown(pStartQFrame->timestamp), timeDown(pEndQFrame->timestamp), qTimeStamp );
break;
}
}
// theStartFrame and theEndFrame should contain the
// two closest keyframes here. now interpolate between them
// TODO: we might be able to cache some of this data...
interpolate_standard_q_frame( pRotations, pStartQFrame, pEndQFrame, qAlpha );
#ifdef __ARAM__
int t_off = 0;
{
// DMA this q track.
int aligned_off = ( (int)pNextTFrame & ~31 );
int size = ( ( *pTSizes - ( aligned_off - (int)pCurrentTFrame ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
t_off = (int)pNextTFrame - aligned_off;
}
#endif // __ARAM__
while ( 1 )
{
if ( pQuickAnim )
{
pQuickAnim->m_quickAnimPointers.pQuickTKey[i] = (char*)pNextTFrame;
}
# ifdef __ARAM__
while ( framecount_active );
# endif // __ARAM__
#ifdef __ARAM__
int bytes = get_compressed_t_frame( &qqq[t_off], pStartTFrame );
t_off += bytes;
pNextTFrame = &pNextTFrame[bytes];
#else
pNextTFrame = get_compressed_t_frame( pNextTFrame, pStartTFrame );
#endif // __ARAM__
if ( pNextTFrame >= pNextTBone )
{
// last frame
*pEndTFrame = *pStartTFrame;
tAlpha = 0.0f;
break;
}
#ifdef __ARAM__
get_compressed_t_frame( &qqq[t_off], pEndTFrame );
#else
get_compressed_t_frame( pNextTFrame, pEndTFrame );
#endif // __ARAM__
if ( tTimeStamp >= timeDown(pStartTFrame->timestamp) && tTimeStamp <= timeDown(pEndTFrame->timestamp) )
{
tAlpha = get_alpha( timeDown(pStartTFrame->timestamp), timeDown(pEndTFrame->timestamp), tTimeStamp );
break;
}
}
interpolate_standard_t_frame( pTranslations, pStartTFrame, pEndTFrame, tAlpha );
}
pCurrentQFrame += *pQSizes;
pCurrentTFrame += *pTSizes;
pQSizes++;
pTSizes++;
pRotations++;
pTranslations++;
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::GetInterpolatedFrames(Mth::Quat* pRotations, Mth::Vector* pTranslations, float time, Nx::CQuickAnim* pQuickAnim )
{
if ( m_flags & nxBONEDANIMFLAGS_USECOMPRESSTABLE )
{
// new partial anims now use the standard GetCompressedInterpolatedFrames function
return GetCompressedInterpolatedFrames(pRotations, pTranslations, time, pQuickAnim);
}
if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
{
Dbg_MsgAssert( 0, ( "Non-compressed partial animations are not supported yet" ) );
}
Dbg_Assert( pRotations );
Dbg_Assert( pTranslations );
Dbg_Assert( !is_hires() );
float qAlpha = 0.0f;
float tAlpha = 0.0f;
// DMA the animation data here.
#ifdef __ARAM__
int size;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
size = ( m_numBones * sizeof(uint32) );
}
else
{
size = 0;
}
if ( m_flags & nxBONEDANIMFLAGS_HIRESFRAMEPOINTERS )
{
size += ( m_numBones * sizeof(SHiResAnimFramePointers) );
}
else
{
size += ( m_numBones * sizeof(SStandardAnimFramePointers) );
}
dma_count( (uint32)mp_perBoneFrames, size );
while ( framecount_active );
// if ( m_flags & nxBONEDANIMFLAGS_PARTIALANIM )
// {
// dma_partial( (uint32)mp_partialAnimData, ( m_numBones * sizeof( uint16 ) * 2 ) );
// }
// while ( framecount_active );
// NsDMA::toMRAM( p_sqqq, (uint32)mp_qFrames, m_num_qFrames * sizeof( CStandardAnimQKey ) );
// NsDMA::toMRAM( p_sttt, (uint32)mp_tFrames, m_num_tFrames * sizeof( CStandardAnimTKey ) );
// while( framecount_active );
#endif // __ARAM__
// find the nearest 2 keyframes
float qTimeStamp = time * 60.0f;
float tTimeStamp = time * 60.0f;
CStandardAnimQKey* pStartQFrame = NULL;
CStandardAnimQKey* pEndQFrame = NULL;
CStandardAnimTKey* pStartTFrame = NULL;
CStandardAnimTKey* pEndTFrame = NULL;
CStandardAnimQKey* pCurrentQFrame = NULL;
CStandardAnimTKey* pCurrentTFrame = NULL;
#ifdef __ARAM__
// pStartQFrame = p_sqqq;
// pEndQFrame = p_sqqq;
//
// pStartTFrame = p_sttt;
// pEndTFrame = p_sttt;
//
// pCurrentQFrame = p_sqqq;
// pCurrentTFrame = p_sttt;
uint32 anim_q_offset = (uint32)mp_qFrames;
uint32 anim_t_offset = (uint32)mp_tFrames;
void * p_bone_frames;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
p_bone_frames = &framecount[m_numBones*2];
}
else
{
p_bone_frames = framecount;
}
#else
pStartQFrame = (CStandardAnimQKey*)mp_qFrames;
pEndQFrame = (CStandardAnimQKey*)mp_qFrames;
pStartTFrame = (CStandardAnimTKey*)mp_tFrames;
pEndTFrame = (CStandardAnimTKey*)mp_tFrames;
pCurrentQFrame = (CStandardAnimQKey*)mp_qFrames;
pCurrentTFrame = (CStandardAnimTKey*)mp_tFrames;
void * p_bone_frames = mp_perBoneFrames;
#endif // __aram__
for ( int i = 0; i < m_numBones; i++ )
{
int numQKeys = get_num_qkeys( p_bone_frames, i );
int numTKeys = get_num_tkeys( p_bone_frames, i );
#ifdef __ARAM__
int q_off = 0;
{
// DMA this q track.
int aligned_off = ( anim_q_offset & ~31 );
int size = ( ( ( sizeof( CStandardAnimQKey ) * numQKeys ) - ( aligned_off - anim_q_offset ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
while ( framecount_active );
q_off = anim_q_offset - aligned_off;
pStartQFrame = (CStandardAnimQKey*)&qqq[q_off];
pEndQFrame = (CStandardAnimQKey*)&qqq[q_off];
pCurrentQFrame = (CStandardAnimQKey*)&qqq[q_off];
}
#endif // __ARAM__
for ( int j = 0; j < numQKeys; j++ )
{
if ( j == (numQKeys-1) )
{
// last frame
pStartQFrame = pCurrentQFrame + j;
pEndQFrame = pCurrentQFrame + j;
qAlpha = 0.0f;
break;
}
else if ( qTimeStamp >= timeDown(pCurrentQFrame[j].timestamp)
&& qTimeStamp <= timeDown(pCurrentQFrame[j+1].timestamp) )
{
pStartQFrame = pCurrentQFrame + j;
pEndQFrame = pCurrentQFrame + j + 1;
qAlpha = get_alpha( timeDown(pStartQFrame->timestamp), timeDown(pEndQFrame->timestamp), qTimeStamp );
break;
}
}
interpolate_q_frame( pRotations,
pStartQFrame,
pEndQFrame,
qAlpha,
is_hires() );
#ifdef __ARAM__
int t_off = 0;
{
// DMA this t track.
int aligned_off = ( anim_t_offset & ~31 );
int size = ( ( ( sizeof( CStandardAnimTKey ) * numTKeys ) - ( aligned_off - anim_t_offset ) ) + 31 ) & ~31;
DCFlushRange ( qqq, size );
framecount_size = size;
framecount_active = 1;
ARQPostRequest ( &framecount_request,
0x55555555, // Owner.
ARQ_TYPE_ARAM_TO_MRAM, // Type.
ARQ_PRIORITY_HIGH, // Priority.
(u32)aligned_off, // Source.
(uint32)qqq, // Dest.
size, // Length.
arqCallback ); // Callback
while ( framecount_active );
t_off = anim_t_offset - aligned_off;
pStartTFrame = (CStandardAnimTKey*)&qqq[t_off];
pEndTFrame = (CStandardAnimTKey*)&qqq[t_off];
pCurrentTFrame = (CStandardAnimTKey*)&qqq[t_off];
}
#endif // __ARAM__
for ( int j = 0; j < numTKeys; j++ )
{
if ( j == (numTKeys-1) )
{
// last frame
pStartTFrame = pCurrentTFrame + j;
pEndTFrame = pCurrentTFrame + j;
tAlpha = 0.0f;
break;
}
else if ( tTimeStamp >= timeDown(pCurrentTFrame[j].timestamp)
&& tTimeStamp <= timeDown(pCurrentTFrame[j+1].timestamp) )
{
pStartTFrame = pCurrentTFrame + j;
pEndTFrame = pCurrentTFrame + j + 1;
tAlpha = get_alpha( timeDown(pStartTFrame->timestamp), timeDown(pEndTFrame->timestamp), tTimeStamp );
break;
}
}
// theStartFrame and theEndFrame should contain the
// two closest keyframes here. now interpolate between them
// TODO: we might be able to cache some of this data...
interpolate_t_frame( pTranslations,
pStartTFrame,
pEndTFrame,
tAlpha,
is_hires() );
#if 0
if ( m_printDebugInfo )
{
// for debug info, if necessary
}
#endif
#ifdef __ARAM__
anim_q_offset += ( sizeof( CStandardAnimQKey ) * numQKeys );
anim_t_offset += ( sizeof( CStandardAnimTKey ) * numTKeys );
#else
pCurrentQFrame += numQKeys;
pCurrentTFrame += numTKeys;
#endif // __ARAM__
pRotations++;
pTranslations++;
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CBonedAnimFrameData::GetBoneName( int index )
{
// only the object anim stores the name of the bones
Dbg_MsgAssert( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA, ( "Bone names are only stored with object anims" ) );
Dbg_MsgAssert( index >= 0 && index < m_numBones, ( "Bone name request out of range %d (0-%d)", index, m_numBones ) );
Dbg_Assert( mp_boneNames );
#ifdef __ARAM__
int size;
if ( m_flags & nxBONEDANIMFLAGS_OBJECTANIMDATA )
{
size = ( m_numBones * sizeof(uint32) );
}
else
{
size = 0;
}
dma_count( (uint32)mp_perBoneFrames, size );
while ( framecount_active );
uint32 * p32 = (uint32*)framecount;
return p32[index];
#else
return mp_boneNames[index];
#endif // __ARAM__
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CBonedAnimFrameData::get_num_customkeys()
{
return m_num_customKeys;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CCustomAnimKey* CBonedAnimFrameData::get_custom_key( int index )
{
Dbg_Assert( index >= 0 && index < get_num_customkeys() );
Dbg_MsgAssert( mpp_customAnimKeyList, ( "custom key list doesn't exist" ) );
return mpp_customAnimKeyList[index];
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::ResetCustomKeys()
{
// this assumes that there's only going to be one
// animcontroller calling this frame data...
// eventually, we might need to move this
// into CReferencedFrameData...
int customKeyCount = get_num_customkeys();
for ( int i = 0; i < customKeyCount; i++ )
{
CCustomAnimKey* pKey = get_custom_key(i);
pKey->SetActive( true );
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CBonedAnimFrameData::ProcessCustomKeys( float startTime, float endTime, Obj::CObject* pObject, bool inclusive )
{
// for each key,
// see if it's between the start and end time
// start_time <= time < end_time
// get it into frames...
startTime *= 60.0f;
endTime *= 60.0f;
int customKeyCount = get_num_customkeys();
for ( int i = 0; i < customKeyCount; i++ )
{
CCustomAnimKey* pKey = get_custom_key(i);
if ( pKey->WithinRange( startTime, endTime, inclusive ) )
{
// printf( "Processing key at %f (%f %f)\n", custom_key_time, startTime, endTime );
pKey->ProcessKey( pObject );
}
else
{
// printf( "Not processing key at %f (%f %f)\n", custom_key_time, startTime, endTime );
}
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
} // namespace Gfx