1785 lines
50 KiB
C++
1785 lines
50 KiB
C++
|
|
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "Anim.h"
|
|
#include "../../framework/Licensee.h"
|
|
|
|
bool idAnimManager::forceExport = false;
|
|
|
|
idCVar anim_reduced( "anim_reduced", "1", CVAR_BOOL|CVAR_ARCHIVE, "" );
|
|
idCVar r_writeAnimB( "r_writeAnimB", "0", CVAR_BOOL, "Write out binary versions of animations." );
|
|
idCVar r_loadAnimB( "r_loadAnimB", "1", CVAR_BOOL, "Attempt loading of binary version of animations." );
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idAnimBlendNetworkInfo_Minimal
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
==================
|
|
idAnimBlendNetworkInfo_Minimal::MakeDefault
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::MakeDefault( void ) {
|
|
startTime = 0;
|
|
endTime = 0;
|
|
blendStartTime = 0;
|
|
blendDuration = 0;
|
|
blendStartValue = 0.f;
|
|
blendEndValue = 0.f;
|
|
animNum = -1;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlendNetworkInfo_Minimal::operator=
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::operator=( const idAnimBlend& anim ) {
|
|
startTime = anim.starttime;
|
|
endTime = anim.endtime;
|
|
blendStartTime = anim.blendStartTime;
|
|
blendDuration = anim.blendDuration;
|
|
blendStartValue = anim.blendStartValue;
|
|
blendEndValue = anim.blendEndValue;
|
|
animNum = anim.animNum;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlendNetworkInfo_Minimal::Write
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::Write( idAnimBlend& anim ) const {
|
|
anim.starttime = startTime;
|
|
anim.endtime = endTime;
|
|
anim.blendStartTime = blendStartTime;
|
|
anim.blendDuration = blendDuration;
|
|
anim.blendStartValue = blendStartValue;
|
|
anim.blendEndValue = blendEndValue;
|
|
anim.animNum = animNum;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlendNetworkInfo_Minimal::operator==
|
|
==================
|
|
*/
|
|
bool idAnimBlend::idAnimBlendNetworkInfo_Minimal::operator==( const idAnimBlendNetworkInfo_Minimal& rhs ) const {
|
|
return startTime == rhs.startTime &&
|
|
endTime == rhs.endTime &&
|
|
blendStartTime == rhs.blendStartTime &&
|
|
blendDuration == rhs.blendDuration &&
|
|
blendStartValue == rhs.blendStartValue &&
|
|
blendEndValue == rhs.blendEndValue &&
|
|
animNum == rhs.animNum;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlendNetworkInfo_Minimal::operator==
|
|
==================
|
|
*/
|
|
bool idAnimBlend::idAnimBlendNetworkInfo_Minimal::operator==( const idAnimBlend& rhs ) const {
|
|
return startTime == rhs.starttime &&
|
|
endTime == rhs.endtime &&
|
|
blendStartTime == rhs.blendStartTime &&
|
|
blendDuration == rhs.blendDuration &&
|
|
blendStartValue == rhs.blendStartValue &&
|
|
blendEndValue == rhs.blendEndValue &&
|
|
animNum == rhs.animNum;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlend::idAnimBlendNetworkInfo_Minimal::Read
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::Read( const idAnimBlendNetworkInfo_Minimal& base, const idBitMsg& msg ) {
|
|
startTime = msg.ReadDeltaLong( base.startTime );
|
|
endTime = msg.ReadDeltaLong( base.endTime );
|
|
blendStartTime = msg.ReadDeltaLong( base.blendStartTime );
|
|
blendDuration = msg.ReadDeltaLong( base.blendDuration );
|
|
blendStartValue = msg.ReadDeltaFloat( base.blendStartValue );
|
|
blendEndValue = msg.ReadDeltaFloat( base.blendEndValue );
|
|
animNum = msg.ReadDeltaShort( base.animNum );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlend::idAnimBlendNetworkInfo_Minimal::Write
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::Write( const idAnimBlendNetworkInfo_Minimal& base, idBitMsg& msg ) const {
|
|
msg.WriteDeltaLong( base.startTime, startTime );
|
|
msg.WriteDeltaLong( base.endTime, endTime );
|
|
msg.WriteDeltaLong( base.blendStartTime, blendStartTime );
|
|
msg.WriteDeltaLong( base.blendDuration, blendDuration );
|
|
msg.WriteDeltaFloat( base.blendStartValue,blendStartValue );
|
|
msg.WriteDeltaFloat( base.blendEndValue, blendEndValue );
|
|
msg.WriteDeltaShort( base.animNum, animNum );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlend::idAnimBlendNetworkInfo_Minimal::Read
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::Read( idFile* file ) {
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idAnimBlend::idAnimBlendNetworkInfo_Minimal::Write
|
|
==================
|
|
*/
|
|
void idAnimBlend::idAnimBlendNetworkInfo_Minimal::Write( idFile* file ) const {
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idMD5Anim
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::idMD5Anim
|
|
====================
|
|
*/
|
|
idMD5Anim::idMD5Anim() {
|
|
ref_count = 0;
|
|
numFrames = 0;
|
|
numJoints = 0;
|
|
frameRate = 24;
|
|
animLength = 0;
|
|
reduced = false;
|
|
totaldelta.Zero();
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::idMD5Anim
|
|
====================
|
|
*/
|
|
idMD5Anim::~idMD5Anim() {
|
|
Free();
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::Free
|
|
====================
|
|
*/
|
|
void idMD5Anim::Free( void ) {
|
|
numFrames = 0;
|
|
numJoints = 0;
|
|
frameRate = 24;
|
|
animLength = 0;
|
|
reduced = false;
|
|
name = "";
|
|
|
|
totaldelta.Zero();
|
|
|
|
jointInfo.Clear();
|
|
bounds.Clear();
|
|
componentFrames.Clear();
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::NumFrames
|
|
====================
|
|
*/
|
|
int idMD5Anim::NumFrames( void ) const {
|
|
return numFrames;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::NumJoints
|
|
====================
|
|
*/
|
|
int idMD5Anim::NumJoints( void ) const {
|
|
return numJoints;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::Length
|
|
====================
|
|
*/
|
|
int idMD5Anim::Length( void ) const {
|
|
return animLength;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idMD5Anim::TotalMovementDelta
|
|
=====================
|
|
*/
|
|
const idVec3 &idMD5Anim::TotalMovementDelta( void ) const {
|
|
return totaldelta;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idMD5Anim::TotalMovementDelta
|
|
=====================
|
|
*/
|
|
const char *idMD5Anim::Name( void ) const {
|
|
return name;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::Reload
|
|
====================
|
|
*/
|
|
bool idMD5Anim::Reload( void ) {
|
|
idStr filename;
|
|
|
|
filename = name;
|
|
Free();
|
|
|
|
return LoadAnim( filename );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::Allocated
|
|
====================
|
|
*/
|
|
size_t idMD5Anim::Allocated( void ) const {
|
|
size_t size = bounds.Allocated() + jointInfo.Allocated() + baseFrame.Allocated() + componentFrames.Allocated() + name.Allocated();
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::LoadAnim
|
|
====================
|
|
*/
|
|
|
|
ID_INLINE short AssertShortRange( int value ) {
|
|
assert( value >= -( 1 << ( sizeof( short ) * 8 - 1 ) ) );
|
|
assert( value < ( 1 << ( sizeof( short ) * 8 - 1 ) ) );
|
|
return (short) value;
|
|
}
|
|
|
|
bool idMD5Anim::LoadAnim( const char *filename ) {
|
|
int version;
|
|
idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
|
|
idToken token;
|
|
int i, j;
|
|
int num;
|
|
bool offsetwarning = false;
|
|
|
|
int skipFrames = 2;
|
|
|
|
if ( !parser.LoadFile( filename ) ) {
|
|
return false;
|
|
}
|
|
|
|
Free();
|
|
|
|
name = filename;
|
|
|
|
parser.ExpectTokenString( MD5_VERSION_STRING );
|
|
version = parser.ParseInt();
|
|
if ( version != MD5_VERSION ) {
|
|
// ARNOUT: FIXME: BACKWARDS COMPATIBILITY
|
|
if ( version != 10 ) {
|
|
parser.Error( "Invalid version %d. Should be version %d", version, MD5_VERSION );
|
|
}
|
|
}
|
|
|
|
// skip the commandline
|
|
parser.ExpectTokenString( "commandline" );
|
|
parser.ReadToken( &token );
|
|
|
|
// parse num frames
|
|
parser.ExpectTokenString( "numFrames" );
|
|
numFrames = parser.ParseInt();
|
|
if ( numFrames <= 0 ) {
|
|
parser.Error( "Invalid number of frames: %d", numFrames );
|
|
}
|
|
|
|
// parse num joints
|
|
parser.ExpectTokenString( "numJoints" );
|
|
numJoints = parser.ParseInt();
|
|
if ( numJoints <= 0 ) {
|
|
parser.Error( "Invalid number of joints: %d", numJoints );
|
|
}
|
|
|
|
// parse frame rate
|
|
parser.ExpectTokenString( "frameRate" );
|
|
frameRate = parser.ParseInt();
|
|
if ( frameRate < 0 ) {
|
|
parser.Error( "Invalid frame rate: %d", frameRate );
|
|
}
|
|
|
|
// parse number of animated components
|
|
parser.ExpectTokenString( "numAnimatedComponents" );
|
|
numAnimatedComponents = parser.ParseInt();
|
|
if ( ( numAnimatedComponents < 0 ) || ( numAnimatedComponents > numJoints * 6 ) ) {
|
|
parser.Error( "Invalid number of animated components: %d", numAnimatedComponents );
|
|
}
|
|
|
|
// parse the hierarchy
|
|
jointInfo.SetGranularity( 1 );
|
|
jointInfo.SetNum( numJoints );
|
|
parser.ExpectTokenString( "hierarchy" );
|
|
parser.ExpectTokenString( "{" );
|
|
for( i = 0; i < numJoints; i++ ) {
|
|
parser.ReadToken( &token );
|
|
jointInfo[ i ].nameIndex = AssertShortRange( animationLib.JointIndex( token ) );
|
|
|
|
// parse parent num
|
|
jointInfo[ i ].parentNum = AssertShortRange( parser.ParseInt() );
|
|
if ( jointInfo[ i ].parentNum >= i ) {
|
|
parser.Error( "Invalid parent num: %d", jointInfo[ i ].parentNum );
|
|
}
|
|
|
|
if ( ( i != 0 ) && ( jointInfo[ i ].parentNum < 0 ) ) {
|
|
parser.Error( "Animations may have only one root joint" );
|
|
}
|
|
|
|
// parse anim bits
|
|
jointInfo[ i ].animBits = AssertShortRange( parser.ParseInt() );
|
|
if ( jointInfo[ i ].animBits & ~63 ) {
|
|
parser.Error( "Invalid anim bits: %d", jointInfo[ i ].animBits );
|
|
}
|
|
|
|
// parse first component
|
|
jointInfo[ i ].firstComponent = AssertShortRange( parser.ParseInt() );
|
|
if ( ( numAnimatedComponents > 0 ) && ( ( jointInfo[ i ].firstComponent < 0 ) || ( jointInfo[ i ].firstComponent >= numAnimatedComponents ) ) ) {
|
|
parser.Error( "Invalid first component: %d", jointInfo[ i ].firstComponent );
|
|
}
|
|
}
|
|
|
|
parser.ExpectTokenString( "}" );
|
|
|
|
// parse bounds
|
|
parser.ExpectTokenString( "bounds" );
|
|
parser.ExpectTokenString( "{" );
|
|
bounds.SetGranularity( 1 );
|
|
bounds.SetNum( numFrames );
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
idBounds b;
|
|
parser.Parse1DMatrix( 3, b[ 0 ].ToFloatPtr() );
|
|
parser.Parse1DMatrix( 3, b[ 1 ].ToFloatPtr() );
|
|
bounds[i].SetBounds( b );
|
|
}
|
|
parser.ExpectTokenString( "}" );
|
|
|
|
// parse base frame
|
|
baseFrame.SetGranularity( 1 );
|
|
baseFrame.SetNum( numJoints );
|
|
parser.ExpectTokenString( "baseframe" );
|
|
parser.ExpectTokenString( "{" );
|
|
for( i = 0; i < numJoints; i++ ) {
|
|
idVec3 t;
|
|
idCQuat q;
|
|
|
|
parser.Parse1DMatrix( 3, t.ToFloatPtr() );
|
|
parser.Parse1DMatrix( 3, q.ToFloatPtr() );
|
|
|
|
t.FixDenormals();
|
|
q.FixDenormals();
|
|
|
|
if ( !offsetwarning ) {
|
|
if ( fabsf( t.x ) >= idCompressedJointQuat::MAX_BONE_LENGTH ||
|
|
fabsf( t.y ) >= idCompressedJointQuat::MAX_BONE_LENGTH ||
|
|
fabsf( t.z ) >= idCompressedJointQuat::MAX_BONE_LENGTH ) {
|
|
int jointNum = jointInfo[ i ].nameIndex;
|
|
gameLocal.Warning( "WARNING: bone offset of '%s' joint '%s' greater than %i",
|
|
filename,
|
|
animationLib.JointName( jointNum ),
|
|
idCompressedJointQuat::MAX_BONE_LENGTH );
|
|
|
|
offsetwarning = true;
|
|
}
|
|
}
|
|
|
|
baseFrame[ i ].t[0] = idCompressedJointQuat::OffsetToShort( t.x );
|
|
baseFrame[ i ].t[1] = idCompressedJointQuat::OffsetToShort( t.y );
|
|
baseFrame[ i ].t[2] = idCompressedJointQuat::OffsetToShort( t.z );
|
|
baseFrame[ i ].q[0] = idCompressedJointQuat::QuatToShort( q.x );
|
|
baseFrame[ i ].q[1] = idCompressedJointQuat::QuatToShort( q.y );
|
|
baseFrame[ i ].q[2] = idCompressedJointQuat::QuatToShort( q.z );
|
|
}
|
|
parser.ExpectTokenString( "}" );
|
|
|
|
// parse frames
|
|
componentFrames.SetGranularity( 1 );
|
|
componentFrames.SetNum( numAnimatedComponents * numFrames );
|
|
|
|
short *componentPtr = componentFrames.Begin();
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
parser.ExpectTokenString( "frame" );
|
|
num = parser.ParseInt();
|
|
if ( num != i ) {
|
|
parser.Error( "Expected frame number %d", i );
|
|
}
|
|
parser.ExpectTokenString( "{" );
|
|
|
|
for ( j = 0; j < numJoints; j++ ) {
|
|
int animBits = jointInfo[j].animBits;
|
|
if ( animBits & ANIM_TX ) {
|
|
float x = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::OffsetToShort( x );
|
|
}
|
|
if ( animBits & ANIM_TY ) {
|
|
float y = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::OffsetToShort( y );
|
|
}
|
|
if ( animBits & ANIM_TZ ) {
|
|
float z = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::OffsetToShort( z );
|
|
}
|
|
if ( animBits & ANIM_QX ) {
|
|
float x = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::QuatToShort( x );
|
|
}
|
|
if ( animBits & ANIM_QY ) {
|
|
float y = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::QuatToShort( y );
|
|
}
|
|
if ( animBits & ANIM_QZ ) {
|
|
float z = parser.ParseFloat();
|
|
*componentPtr++ = idCompressedJointQuat::QuatToShort( z );
|
|
}
|
|
}
|
|
|
|
parser.ExpectTokenString( "}" );
|
|
}
|
|
|
|
// get total move delta
|
|
if ( !numAnimatedComponents ) {
|
|
totaldelta.Zero();
|
|
} else {
|
|
componentPtr = &componentFrames[ jointInfo[ 0 ].firstComponent ];
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t[0];
|
|
}
|
|
totaldelta.x = idCompressedJointQuat::ShortToOffset( componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ] );
|
|
componentPtr++;
|
|
} else {
|
|
totaldelta.x = 0.0f;
|
|
}
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t[1];
|
|
}
|
|
totaldelta.y = idCompressedJointQuat::ShortToOffset( componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ] );
|
|
componentPtr++;
|
|
} else {
|
|
totaldelta.y = 0.0f;
|
|
}
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t[2];
|
|
}
|
|
totaldelta.z = idCompressedJointQuat::ShortToOffset( componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ] );
|
|
} else {
|
|
totaldelta.z = 0.0f;
|
|
}
|
|
}
|
|
baseFrame[ 0 ].ClearOffset();
|
|
|
|
// we don't count last frame because it would cause a 1 frame pause at the end
|
|
animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate;
|
|
|
|
if ( numFrames > 4 && numAnimatedComponents && anim_reduced.GetBool() && !r_writeAnimB.GetBool() ) {
|
|
Resample();
|
|
}
|
|
|
|
// done
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::Resample
|
|
====================
|
|
*/
|
|
void idMD5Anim::Resample( void ) {
|
|
|
|
if ( reduced ) {
|
|
return;
|
|
}
|
|
|
|
int idealFrames = numFrames/2;
|
|
idList<short> resampledFrames;
|
|
resampledFrames.SetGranularity( 1 );
|
|
resampledFrames.SetNum( numAnimatedComponents * idealFrames );
|
|
|
|
idCompressedJointQuat *compressedJoints = (idCompressedJointQuat *)_alloca16( numJoints * sizeof( compressedJoints[0] ) );
|
|
idCompressedJointQuat *compressedBlendJoints = (idCompressedJointQuat *)_alloca16( numJoints * sizeof( compressedBlendJoints[0] ) );
|
|
idJointQuat *joints = (idJointQuat *)_alloca16( numJoints * sizeof( joints[0] ) );
|
|
idJointQuat *blendJoints = (idJointQuat *)_alloca16( numJoints * sizeof( blendJoints[0] ) );
|
|
int *baseIndex = (int*)_alloca16( numJoints * sizeof( baseIndex[0] ) );
|
|
for (int i=0; i<numJoints; i++) {
|
|
baseIndex[i] = i;
|
|
}
|
|
|
|
for (int i=0; i<idealFrames; i++) {
|
|
float srcf = (i*(numFrames-1)) / (idealFrames-1);
|
|
int srci = (int)idMath::Floor( srcf );
|
|
float blend = srcf - srci;
|
|
if ( i != srci ) {
|
|
bounds[i] = bounds[srci];
|
|
}
|
|
{
|
|
short *destPtr = &resampledFrames[ i * numAnimatedComponents ];
|
|
short *srcPtr = &componentFrames[ srci * numAnimatedComponents ];
|
|
short *nextSrcPtr;
|
|
if ( (srci+1) < numFrames ) {
|
|
nextSrcPtr = &componentFrames[ (srci+1) * numAnimatedComponents ];
|
|
} else {
|
|
nextSrcPtr = srcPtr;
|
|
}
|
|
int numBaseIndex = 0;
|
|
for ( int j = 0; j < numJoints; j++ ) {
|
|
const jointAnimInfo_t * infoPtr = &jointInfo[j];
|
|
int animBits = infoPtr->animBits;
|
|
if ( animBits == 0 ) {
|
|
continue;
|
|
}
|
|
baseIndex[numBaseIndex] = numBaseIndex;
|
|
idCompressedJointQuat *jointPtr = &compressedJoints[numBaseIndex];
|
|
idCompressedJointQuat *blendPtr = &compressedBlendJoints[numBaseIndex];
|
|
const short *jointframe1 = srcPtr + infoPtr->firstComponent;
|
|
const short *jointframe2 = nextSrcPtr + infoPtr->firstComponent;
|
|
|
|
*jointPtr = baseFrame[j];
|
|
|
|
switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
|
|
case 0:
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
break;
|
|
case ANIM_TX:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TY:
|
|
jointPtr->t[1] = jointframe1[0];
|
|
blendPtr->t[1] = jointframe2[0];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TZ:
|
|
jointPtr->t[2] = jointframe1[0];
|
|
blendPtr->t[2] = jointframe2[0];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TX|ANIM_TY:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[1] = jointframe1[1];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointframe2[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[2] = jointframe1[1];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[2] = jointframe2[1];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[1] = jointframe1[0];
|
|
jointPtr->t[2] = jointframe1[1];
|
|
blendPtr->t[1] = jointframe2[0];
|
|
blendPtr->t[2] = jointframe2[1];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[1] = jointframe1[1];
|
|
jointPtr->t[2] = jointframe1[2];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointframe2[1];
|
|
blendPtr->t[2] = jointframe2[2];
|
|
jointframe1 += 3;
|
|
jointframe2 += 3;
|
|
break;
|
|
}
|
|
|
|
switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
|
|
case 0:
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QX:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QY:
|
|
jointPtr->q[1] = jointframe1[0];
|
|
blendPtr->q[1] = jointframe2[0];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QZ:
|
|
jointPtr->q[2] = jointframe1[0];
|
|
blendPtr->q[2] = jointframe2[0];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
break;
|
|
case ANIM_QX|ANIM_QY:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[1] = jointframe1[1];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointframe2[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QX|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[2] = jointframe1[1];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[2] = jointframe2[1];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
break;
|
|
case ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[1] = jointframe1[0];
|
|
jointPtr->q[2] = jointframe1[1];
|
|
blendPtr->q[1] = jointframe2[0];
|
|
blendPtr->q[2] = jointframe2[1];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
break;
|
|
case ANIM_QX|ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[1] = jointframe1[1];
|
|
jointPtr->q[2] = jointframe1[2];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointframe2[1];
|
|
blendPtr->q[2] = jointframe2[2];
|
|
break;
|
|
}
|
|
numBaseIndex++;
|
|
}
|
|
blendJoints = (idJointQuat *)_alloca16( baseFrame.Num() * sizeof( blendJoints[ 0 ] ) );
|
|
|
|
SIMDProcessor->DecompressJoints( joints, compressedJoints, baseIndex, numBaseIndex );
|
|
SIMDProcessor->DecompressJoints( blendJoints, compressedBlendJoints, baseIndex, numBaseIndex );
|
|
|
|
SIMDProcessor->BlendJoints( joints, blendJoints, 1.f-blend, baseIndex, numBaseIndex );
|
|
numBaseIndex = 0;
|
|
for ( int j = 0; j < numJoints; j++ ) {
|
|
const jointAnimInfo_t * infoPtr = &jointInfo[j];
|
|
int animBits = infoPtr->animBits;
|
|
if ( animBits == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
idJointQuat const &curjoint = joints[numBaseIndex];
|
|
idCQuat cq = curjoint.q.ToCQuat();
|
|
idCompressedJointQuat cj;
|
|
cj.t[0] = idCompressedJointQuat::OffsetToShort( curjoint.t.x );
|
|
cj.t[1] = idCompressedJointQuat::OffsetToShort( curjoint.t.y );
|
|
cj.t[2] = idCompressedJointQuat::OffsetToShort( curjoint.t.z );
|
|
cj.q[0] = idCompressedJointQuat::QuatToShort( cq.x );
|
|
cj.q[1] = idCompressedJointQuat::QuatToShort( cq.y );
|
|
cj.q[2] = idCompressedJointQuat::QuatToShort( cq.z );
|
|
|
|
short *output = &destPtr[ infoPtr->firstComponent ];
|
|
if ( animBits & (ANIM_TX) ) {
|
|
*output++ = cj.t[0];
|
|
}
|
|
if ( animBits & (ANIM_TY) ) {
|
|
*output++ = cj.t[1];
|
|
}
|
|
if ( animBits & (ANIM_TZ) ) {
|
|
*output++ = cj.t[2];
|
|
}
|
|
if ( animBits & (ANIM_QX) ) {
|
|
*output++ = cj.q[0];
|
|
}
|
|
if ( animBits & (ANIM_QY) ) {
|
|
*output++ = cj.q[1];
|
|
}
|
|
if ( animBits & (ANIM_QZ) ) {
|
|
*output++ = cj.q[2];
|
|
}
|
|
|
|
numBaseIndex++;
|
|
}
|
|
}
|
|
}
|
|
int nb = numFrames;
|
|
int fr = frameRate;
|
|
frameRate = (frameRate * idealFrames) / numFrames;//(((numFrames - 1) * 1000) + animLength - 1) / (animLength);
|
|
numFrames = idealFrames;
|
|
animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate;
|
|
|
|
bounds.SetGranularity( 1 );
|
|
bounds.SetNum( numFrames );
|
|
componentFrames = resampledFrames;
|
|
|
|
reduced = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::IncreaseRefs
|
|
====================
|
|
*/
|
|
void idMD5Anim::IncreaseRefs( void ) const {
|
|
ref_count++;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::DecreaseRefs
|
|
====================
|
|
*/
|
|
void idMD5Anim::DecreaseRefs( void ) const {
|
|
ref_count--;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::NumRefs
|
|
====================
|
|
*/
|
|
int idMD5Anim::NumRefs( void ) const {
|
|
return ref_count;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetFrameBlend
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetFrameBlend( int framenum, frameBlend_t &frame ) const {
|
|
frame.cycleCount = 0;
|
|
frame.backlerp = 0.0f;
|
|
frame.frontlerp = 1.0f;
|
|
|
|
// frame 1 is first frame
|
|
framenum--;
|
|
if ( framenum < 0 ) {
|
|
framenum = 0;
|
|
} else if ( framenum >= numFrames ) {
|
|
framenum = numFrames - 1;
|
|
}
|
|
|
|
frame.frame1 = framenum;
|
|
frame.frame2 = framenum;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::ConvertTimeToFrame
|
|
====================
|
|
*/
|
|
void idMD5Anim::ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const {
|
|
int frameTime;
|
|
int frameNum;
|
|
|
|
if ( numFrames <= 1 ) {
|
|
frame.frame1 = 0;
|
|
frame.frame2 = 0;
|
|
frame.backlerp = 0.0f;
|
|
frame.frontlerp = 1.0f;
|
|
frame.cycleCount = 0;
|
|
return;
|
|
}
|
|
|
|
if ( time <= 0 ) {
|
|
frame.frame1 = 0;
|
|
frame.frame2 = 1;
|
|
frame.backlerp = 0.0f;
|
|
frame.frontlerp = 1.0f;
|
|
frame.cycleCount = 0;
|
|
return;
|
|
}
|
|
|
|
frameTime = time * frameRate;
|
|
frameNum = frameTime / 1000;
|
|
frame.cycleCount = frameNum / ( numFrames - 1 );
|
|
|
|
if ( ( cyclecount > 0 ) && ( frame.cycleCount >= cyclecount ) ) {
|
|
frame.cycleCount = cyclecount - 1;
|
|
frame.frame1 = numFrames - 1;
|
|
frame.frame2 = frame.frame1;
|
|
frame.backlerp = 0.0f;
|
|
frame.frontlerp = 1.0f;
|
|
return;
|
|
}
|
|
|
|
frame.frame1 = frameNum % ( numFrames - 1 );
|
|
frame.frame2 = frame.frame1 + 1;
|
|
if ( frame.frame2 >= numFrames ) {
|
|
frame.frame2 = 0;
|
|
}
|
|
|
|
frame.backlerp = ( frameTime % 1000 ) * 0.001f;
|
|
frame.frontlerp = 1.0f - frame.backlerp;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetOrigin
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetOrigin( idVec3 &offset, int time, int cyclecount ) const {
|
|
frameBlend_t frame;
|
|
|
|
offset[0] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[0] );
|
|
offset[1] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[1] );
|
|
offset[2] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[2] );
|
|
|
|
if ( !( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) ) {
|
|
// just use the baseframe
|
|
return;
|
|
}
|
|
|
|
ConvertTimeToFrame( time, cyclecount, frame );
|
|
|
|
const short *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
|
|
const short *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
|
|
offset.x = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
componentPtr1++;
|
|
componentPtr2++;
|
|
}
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
|
|
offset.y = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
componentPtr1++;
|
|
componentPtr2++;
|
|
}
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
|
|
offset.z = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
}
|
|
|
|
if ( frame.cycleCount ) {
|
|
offset += totaldelta * ( float )frame.cycleCount;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetOriginRotation
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const {
|
|
frameBlend_t frame;
|
|
int animBits;
|
|
|
|
animBits = jointInfo[ 0 ].animBits;
|
|
if ( !( animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) ) ) {
|
|
// just use the baseframe
|
|
rotation[0] = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
rotation[1] = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
rotation[2] = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
rotation.w = rotation.CalcW();
|
|
return;
|
|
}
|
|
|
|
ConvertTimeToFrame( time, cyclecount, frame );
|
|
|
|
const short *jointframe1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
|
|
const short *jointframe2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
|
|
|
|
if ( animBits & ANIM_TX ) {
|
|
jointframe1++;
|
|
jointframe2++;
|
|
}
|
|
|
|
if ( animBits & ANIM_TY ) {
|
|
jointframe1++;
|
|
jointframe2++;
|
|
}
|
|
|
|
if ( animBits & ANIM_TZ ) {
|
|
jointframe1++;
|
|
jointframe2++;
|
|
}
|
|
|
|
idQuat q1;
|
|
idQuat q2;
|
|
|
|
switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
|
|
case ANIM_QX:
|
|
q1.x = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q1.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QY:
|
|
q1.y = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q1.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QZ:
|
|
q1.z = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q1.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q1.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QX|ANIM_QY:
|
|
q1.x = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q1.y = idCompressedJointQuat::ShortToQuat( jointframe1[1] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( jointframe2[1] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[2] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QX|ANIM_QZ:
|
|
q1.x = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( jointframe1[1] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( jointframe2[1] );
|
|
q1.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[1] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QY|ANIM_QZ:
|
|
q1.y = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( jointframe1[1] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( jointframe2[1] );
|
|
q1.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( baseFrame[ 0 ].q[0] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
case ANIM_QX|ANIM_QY|ANIM_QZ:
|
|
q1.x = idCompressedJointQuat::ShortToQuat( jointframe1[0] );
|
|
q1.y = idCompressedJointQuat::ShortToQuat( jointframe1[1] );
|
|
q1.z = idCompressedJointQuat::ShortToQuat( jointframe1[2] );
|
|
q2.x = idCompressedJointQuat::ShortToQuat( jointframe2[0] );
|
|
q2.y = idCompressedJointQuat::ShortToQuat( jointframe2[1] );
|
|
q2.z = idCompressedJointQuat::ShortToQuat( jointframe2[2] );
|
|
q1.w = q1.CalcW();
|
|
q2.w = q2.CalcW();
|
|
break;
|
|
}
|
|
|
|
rotation.Slerp( q1, q2, frame.backlerp );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetBounds
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetBounds( idBounds &bnds, int time, int cyclecount ) const {
|
|
frameBlend_t frame;
|
|
idVec3 offset;
|
|
|
|
ConvertTimeToFrame( time, cyclecount, frame );
|
|
|
|
bnds = bounds[ frame.frame1 ].ToBounds();
|
|
bnds.AddBounds( bounds[ frame.frame2 ].ToBounds() );
|
|
|
|
// origin position
|
|
offset[0] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[0] );
|
|
offset[1] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[1] );
|
|
offset[2] = idCompressedJointQuat::ShortToOffset( baseFrame[ 0 ].t[2] );
|
|
|
|
if ( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) {
|
|
const short *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
|
|
const short *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
|
|
offset.x = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
componentPtr1++;
|
|
componentPtr2++;
|
|
}
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
|
|
offset.y = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
componentPtr1++;
|
|
componentPtr2++;
|
|
}
|
|
|
|
if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
|
|
offset.z = idCompressedJointQuat::ShortToOffset( *componentPtr1 ) * frame.frontlerp + idCompressedJointQuat::ShortToOffset( *componentPtr2 ) * frame.backlerp;
|
|
}
|
|
}
|
|
|
|
bnds[ 0 ] -= offset;
|
|
bnds[ 1 ] -= offset;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetInterpolatedFrame
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const {
|
|
int i, numLerpJoints;
|
|
const short * frame1;
|
|
const short * frame2;
|
|
const short * jointframe1;
|
|
const short * jointframe2;
|
|
const jointAnimInfo_t * infoPtr;
|
|
int animBits;
|
|
idJointQuat * blendJoints;
|
|
idCompressedJointQuat * compressedJoints;
|
|
idCompressedJointQuat * compressedBlendJoints;
|
|
idCompressedJointQuat * jointPtr;
|
|
idCompressedJointQuat * blendPtr;
|
|
int * lerpIndex;
|
|
int * baseIndex;
|
|
|
|
// FIXME: have global static ?
|
|
// index with all joints
|
|
baseIndex = (int *)_alloca16( baseFrame.Num() * sizeof( baseIndex[ 0 ] ) );
|
|
for ( i = 0; i < baseFrame.Num(); i++ ) {
|
|
baseIndex[i] = i;
|
|
}
|
|
|
|
if ( !numAnimatedComponents ) {
|
|
// just use the base frame
|
|
SIMDProcessor->DecompressJoints( joints, baseFrame.Begin(), baseIndex, baseFrame.Num() );
|
|
return;
|
|
}
|
|
|
|
compressedJoints = (idCompressedJointQuat *)_alloca16( baseFrame.Num() * sizeof( compressedJoints[0] ) );
|
|
compressedBlendJoints = (idCompressedJointQuat *)_alloca16( baseFrame.Num() * sizeof( compressedBlendJoints[0] ) );
|
|
|
|
SIMDProcessor->Memcpy( compressedJoints, baseFrame.Begin(), baseFrame.Num() * sizeof( compressedJoints[0] ) );
|
|
|
|
lerpIndex = (int *)_alloca16( baseFrame.Num() * sizeof( lerpIndex[ 0 ] ) );
|
|
numLerpJoints = 0;
|
|
|
|
frame1 = &componentFrames[ frame.frame1 * numAnimatedComponents ];
|
|
frame2 = &componentFrames[ frame.frame2 * numAnimatedComponents ];
|
|
|
|
// delta decompression relative to base frame
|
|
for ( i = 0; i < numIndexes; i++ ) {
|
|
int j = index[i];
|
|
infoPtr = &jointInfo[j];
|
|
|
|
animBits = infoPtr->animBits;
|
|
if ( animBits == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
jointPtr = &compressedJoints[j];
|
|
blendPtr = &compressedBlendJoints[j];
|
|
|
|
lerpIndex[numLerpJoints++] = j;
|
|
|
|
jointframe1 = frame1 + infoPtr->firstComponent;
|
|
jointframe2 = frame2 + infoPtr->firstComponent;
|
|
|
|
switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
|
|
case 0:
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
break;
|
|
case ANIM_TX:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TY:
|
|
jointPtr->t[1] = jointframe1[0];
|
|
blendPtr->t[1] = jointframe2[0];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TZ:
|
|
jointPtr->t[2] = jointframe1[0];
|
|
blendPtr->t[2] = jointframe2[0];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
jointframe1++;
|
|
jointframe2++;
|
|
break;
|
|
case ANIM_TX|ANIM_TY:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[1] = jointframe1[1];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointframe2[1];
|
|
blendPtr->t[2] = jointPtr->t[2];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[2] = jointframe1[1];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[2] = jointframe2[1];
|
|
blendPtr->t[1] = jointPtr->t[1];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[1] = jointframe1[0];
|
|
jointPtr->t[2] = jointframe1[1];
|
|
blendPtr->t[1] = jointframe2[0];
|
|
blendPtr->t[2] = jointframe2[1];
|
|
blendPtr->t[0] = jointPtr->t[0];
|
|
jointframe1 += 2;
|
|
jointframe2 += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe1[0];
|
|
jointPtr->t[1] = jointframe1[1];
|
|
jointPtr->t[2] = jointframe1[2];
|
|
blendPtr->t[0] = jointframe2[0];
|
|
blendPtr->t[1] = jointframe2[1];
|
|
blendPtr->t[2] = jointframe2[2];
|
|
jointframe1 += 3;
|
|
jointframe2 += 3;
|
|
break;
|
|
}
|
|
|
|
switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
|
|
case 0:
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QX:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QY:
|
|
jointPtr->q[1] = jointframe1[0];
|
|
blendPtr->q[1] = jointframe2[0];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QZ:
|
|
jointPtr->q[2] = jointframe1[0];
|
|
blendPtr->q[2] = jointframe2[0];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
break;
|
|
case ANIM_QX|ANIM_QY:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[1] = jointframe1[1];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointframe2[1];
|
|
blendPtr->q[2] = jointPtr->q[2];
|
|
break;
|
|
case ANIM_QX|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[2] = jointframe1[1];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[2] = jointframe2[1];
|
|
blendPtr->q[1] = jointPtr->q[1];
|
|
break;
|
|
case ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[1] = jointframe1[0];
|
|
jointPtr->q[2] = jointframe1[1];
|
|
blendPtr->q[1] = jointframe2[0];
|
|
blendPtr->q[2] = jointframe2[1];
|
|
blendPtr->q[0] = jointPtr->q[0];
|
|
break;
|
|
case ANIM_QX|ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe1[0];
|
|
jointPtr->q[1] = jointframe1[1];
|
|
jointPtr->q[2] = jointframe1[2];
|
|
blendPtr->q[0] = jointframe2[0];
|
|
blendPtr->q[1] = jointframe2[1];
|
|
blendPtr->q[2] = jointframe2[2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
blendJoints = (idJointQuat *)_alloca16( baseFrame.Num() * sizeof( blendJoints[ 0 ] ) );
|
|
|
|
SIMDProcessor->DecompressJoints( joints, compressedJoints, baseIndex, baseFrame.Num() );
|
|
SIMDProcessor->DecompressJoints( blendJoints, compressedBlendJoints, lerpIndex, numLerpJoints );
|
|
|
|
SIMDProcessor->BlendJoints( joints, blendJoints, frame.backlerp, lerpIndex, numLerpJoints );
|
|
|
|
if ( frame.cycleCount ) {
|
|
joints[ 0 ].t += totaldelta * ( float )frame.cycleCount;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::GetSingleFrame
|
|
====================
|
|
*/
|
|
void idMD5Anim::GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const {
|
|
int i;
|
|
const short * frame;
|
|
const short * jointframe;
|
|
int animBits;
|
|
idCompressedJointQuat * compressedJoints;
|
|
idCompressedJointQuat * jointPtr;
|
|
const jointAnimInfo_t * infoPtr;
|
|
int * baseIndex;
|
|
|
|
// FIXME: have global static ?
|
|
// index with all joints
|
|
baseIndex = (int *)_alloca16( baseFrame.Num() * sizeof( baseIndex[ 0 ] ) );
|
|
for ( i = 0; i < baseFrame.Num(); i++ ) {
|
|
baseIndex[i] = i;
|
|
}
|
|
|
|
if ( ( framenum == 0 ) || !numAnimatedComponents ) {
|
|
// just use the base frame
|
|
SIMDProcessor->DecompressJoints( joints, baseFrame.Begin(), baseIndex, baseFrame.Num() );
|
|
return;
|
|
}
|
|
|
|
compressedJoints = (idCompressedJointQuat *)_alloca16( baseFrame.Num() * sizeof( compressedJoints[0] ) );
|
|
|
|
SIMDProcessor->Memcpy( compressedJoints, baseFrame.Begin(), baseFrame.Num() * sizeof( baseFrame[0] ) );
|
|
|
|
frame = &componentFrames[ framenum * numAnimatedComponents ];
|
|
|
|
// delta decompression relative to base frame
|
|
for ( i = 0; i < numIndexes; i++ ) {
|
|
int j = index[i];
|
|
infoPtr = &jointInfo[j];
|
|
|
|
animBits = infoPtr->animBits;
|
|
if ( animBits == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
jointPtr = &compressedJoints[j];
|
|
|
|
jointframe = frame + infoPtr->firstComponent;
|
|
|
|
switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
|
|
case 0:
|
|
break;
|
|
case ANIM_TX:
|
|
jointPtr->t[0] = jointframe[0];
|
|
jointframe++;
|
|
break;
|
|
case ANIM_TY:
|
|
jointPtr->t[1] = jointframe[0];
|
|
jointframe++;
|
|
break;
|
|
case ANIM_TZ:
|
|
jointPtr->t[2] = jointframe[0];
|
|
jointframe++;
|
|
break;
|
|
case ANIM_TX|ANIM_TY:
|
|
jointPtr->t[0] = jointframe[0];
|
|
jointPtr->t[1] = jointframe[1];
|
|
jointframe += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe[0];
|
|
jointPtr->t[2] = jointframe[1];
|
|
jointframe += 2;
|
|
break;
|
|
case ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[1] = jointframe[0];
|
|
jointPtr->t[2] = jointframe[1];
|
|
jointframe += 2;
|
|
break;
|
|
case ANIM_TX|ANIM_TY|ANIM_TZ:
|
|
jointPtr->t[0] = jointframe[0];
|
|
jointPtr->t[1] = jointframe[1];
|
|
jointPtr->t[2] = jointframe[2];
|
|
jointframe += 3;
|
|
break;
|
|
}
|
|
|
|
switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
|
|
case 0:
|
|
break;
|
|
case ANIM_QX:
|
|
jointPtr->q[0] = jointframe[0];
|
|
break;
|
|
case ANIM_QY:
|
|
jointPtr->q[1] = jointframe[0];
|
|
break;
|
|
case ANIM_QZ:
|
|
jointPtr->q[2] = jointframe[0];
|
|
break;
|
|
case ANIM_QX|ANIM_QY:
|
|
jointPtr->q[0] = jointframe[0];
|
|
jointPtr->q[1] = jointframe[1];
|
|
break;
|
|
case ANIM_QX|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe[0];
|
|
jointPtr->q[2] = jointframe[1];
|
|
break;
|
|
case ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[1] = jointframe[0];
|
|
jointPtr->q[2] = jointframe[1];
|
|
break;
|
|
case ANIM_QX|ANIM_QY|ANIM_QZ:
|
|
jointPtr->q[0] = jointframe[0];
|
|
jointPtr->q[1] = jointframe[1];
|
|
jointPtr->q[2] = jointframe[2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
SIMDProcessor->DecompressJoints( joints, compressedJoints, baseIndex, baseFrame.Num() );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idMD5Anim::CheckModelHierarchy
|
|
====================
|
|
*/
|
|
void idMD5Anim::CheckModelHierarchy( const idRenderModel *model ) const {
|
|
int i;
|
|
int jointNum;
|
|
int parent;
|
|
|
|
if ( jointInfo.Num() != model->NumJoints() ) {
|
|
gameLocal.Error( "Model '%s' has different # of joints than anim '%s'", model->Name(), name.c_str() );
|
|
}
|
|
|
|
const idMD5Joint *modelJoints = model->GetJoints();
|
|
for( i = 0; i < jointInfo.Num(); i++ ) {
|
|
jointNum = jointInfo[ i ].nameIndex;
|
|
if ( modelJoints[ i ].name != animationLib.JointName( jointNum ) ) {
|
|
gameLocal.Error( "Model '%s''s joint names don't match anim '%s''s", model->Name(), name.c_str() );
|
|
}
|
|
if ( modelJoints[ i ].parent ) {
|
|
parent = modelJoints[ i ].parent - modelJoints;
|
|
} else {
|
|
parent = -1;
|
|
}
|
|
if ( parent != jointInfo[ i ].parentNum ) {
|
|
gameLocal.Error( "Model '%s' has different joint hierarchy than anim '%s'", model->Name(), name.c_str() );
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idAnimManager
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
====================
|
|
idAnimManager::idAnimManager
|
|
====================
|
|
*/
|
|
idAnimManager::idAnimManager() {
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idAnimManager::~idAnimManager
|
|
====================
|
|
*/
|
|
idAnimManager::~idAnimManager() {
|
|
Shutdown();
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idAnimManager::Shutdown
|
|
====================
|
|
*/
|
|
void idAnimManager::Shutdown( void ) {
|
|
animations.DeleteContents();
|
|
jointnames.Clear();
|
|
jointnamesHash.Free();
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
idMD5Anim::LoadAnimBinary
|
|
==============
|
|
*/
|
|
bool idMD5Anim::LoadAnimBinary( const char *filename ) {
|
|
int ident, version, num;
|
|
|
|
idFile* file = fileSystem->OpenFileRead( filename );
|
|
if ( file == NULL ) {
|
|
// common->Warning( "Couldn't load binary anim, %s", filename );
|
|
return false;
|
|
}
|
|
|
|
#if defined( SD_BUFFERED_FILE_LOADS )
|
|
file = fileSystem->OpenBufferedFile( file );
|
|
#endif
|
|
|
|
Free();
|
|
|
|
file->ReadInt( ident );
|
|
if ( ident != ANIMB_IDENT ) {
|
|
common->Warning( "idMD5Anim::LoadAnimBinary : unknown fileid on '%s'", filename );
|
|
return false;
|
|
}
|
|
|
|
file->ReadInt( version );
|
|
if ( version != ANIMB_VERSION ) {
|
|
common->Warning( "idMD5Anim::LoadAnimBinary : wrong version on '%s' (%i should be %i)", filename, version, ANIMB_VERSION );
|
|
return false;
|
|
}
|
|
|
|
file->ReadInt( numFrames );
|
|
file->ReadInt( frameRate );
|
|
file->ReadInt( animLength );
|
|
file->ReadInt( numJoints );
|
|
file->ReadInt( numAnimatedComponents );
|
|
|
|
file->ReadInt( num );
|
|
bounds.SetGranularity( 1 );
|
|
bounds.SetNum( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
short list[6];
|
|
|
|
file->ReadShort( list[0] );
|
|
file->ReadShort( list[1] );
|
|
file->ReadShort( list[2] );
|
|
file->ReadShort( list[3] );
|
|
file->ReadShort( list[4] );
|
|
file->ReadShort( list[5] );
|
|
|
|
bounds[i].SetBounds( list );
|
|
}
|
|
|
|
file->ReadInt( num );
|
|
jointInfo.SetGranularity( 1 );
|
|
jointInfo.SetNum( num );
|
|
idStr temp;
|
|
for ( int i=0; i<num; i++ ) {
|
|
file->ReadString( temp );
|
|
jointInfo[i].nameIndex = animationLib.JointIndex( temp );
|
|
|
|
file->ReadShort( jointInfo[i].parentNum );
|
|
file->ReadShort( jointInfo[i].animBits );
|
|
file->ReadShort( jointInfo[i].firstComponent );
|
|
}
|
|
|
|
file->ReadInt( num );
|
|
baseFrame.SetGranularity( 1 );
|
|
baseFrame.SetNum( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
file->ReadShort( baseFrame[i].q[0] );
|
|
file->ReadShort( baseFrame[i].q[1] );
|
|
file->ReadShort( baseFrame[i].q[2] );
|
|
file->ReadShort( baseFrame[i].t[0] );
|
|
file->ReadShort( baseFrame[i].t[1] );
|
|
file->ReadShort( baseFrame[i].t[2] );
|
|
}
|
|
|
|
file->ReadInt( num );
|
|
componentFrames.SetGranularity( 1 );
|
|
componentFrames.SetNum( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
file->ReadShort( componentFrames[i] );
|
|
}
|
|
|
|
file->ReadString( name );
|
|
file->ReadVec3( totaldelta );
|
|
|
|
fileSystem->CloseFile( file );
|
|
|
|
if ( numFrames > 4 && numAnimatedComponents && anim_reduced.GetBool() ) {
|
|
Resample();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
idMD5Anim::WriteAnimBinary
|
|
==============
|
|
*/
|
|
bool idMD5Anim::WriteAnimBinary( const char *filename ) {
|
|
int num;
|
|
|
|
idStr str = filename;
|
|
str.StripFileExtension();
|
|
str = str + ".animb";
|
|
|
|
idFile* file = fileSystem->OpenFileWrite( str.c_str(), "fs_savepath" );
|
|
if ( file == NULL ) {
|
|
return false;
|
|
}
|
|
|
|
file->WriteInt( ANIMB_IDENT );
|
|
file->WriteInt( ANIMB_VERSION );
|
|
|
|
file->WriteInt( numFrames );
|
|
file->WriteInt( frameRate );
|
|
file->WriteInt( animLength );
|
|
file->WriteInt( numJoints );
|
|
file->WriteInt( numAnimatedComponents );
|
|
|
|
num = bounds.Num();
|
|
file->WriteInt( num );
|
|
for ( int i = 0; i < num; i++ ) {
|
|
const short *list = bounds[i].GetBounds();
|
|
|
|
file->WriteShort( list[0] );
|
|
file->WriteShort( list[1] );
|
|
file->WriteShort( list[2] );
|
|
file->WriteShort( list[3] );
|
|
file->WriteShort( list[4] );
|
|
file->WriteShort( list[5] );
|
|
}
|
|
|
|
num = jointInfo.Num();
|
|
file->WriteInt( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
jointAnimInfo_t animInfo = jointInfo[i];
|
|
|
|
file->WriteString( animationLib.JointName( animInfo.nameIndex ) );
|
|
|
|
file->WriteShort( animInfo.parentNum );
|
|
file->WriteShort( animInfo.animBits );
|
|
file->WriteShort( animInfo.firstComponent );
|
|
}
|
|
|
|
num = baseFrame.Num();
|
|
file->WriteInt( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
idCompressedJointQuat jointQuat = baseFrame[i];
|
|
|
|
file->WriteShort( jointQuat.q[0] );
|
|
file->WriteShort( jointQuat.q[1] );
|
|
file->WriteShort( jointQuat.q[2] );
|
|
file->WriteShort( jointQuat.t[0] );
|
|
file->WriteShort( jointQuat.t[1] );
|
|
file->WriteShort( jointQuat.t[2] );
|
|
}
|
|
|
|
num = componentFrames.Num();
|
|
file->WriteInt( num );
|
|
for ( int i=0; i<num; i++ ) {
|
|
file->WriteShort( componentFrames[i] );
|
|
}
|
|
|
|
file->WriteString( name );
|
|
file->WriteVec3( totaldelta );
|
|
|
|
fileSystem->CloseFile( file );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idAnimManager::GetAnim
|
|
====================
|
|
*/
|
|
idMD5Anim *idAnimManager::GetAnim( const char *name ) {
|
|
idMD5Anim **animptrptr;
|
|
idMD5Anim *anim;
|
|
bool loaded = false;
|
|
|
|
// see if it has been asked for before
|
|
animptrptr = NULL;
|
|
if ( animations.Get( name, &animptrptr ) ) {
|
|
anim = *animptrptr;
|
|
} else {
|
|
idStr extension;
|
|
idStr filename = name;
|
|
|
|
filename.ExtractFileExtension( extension );
|
|
if ( extension != MD5_ANIM_EXT ) {
|
|
return NULL;
|
|
}
|
|
|
|
anim = new idMD5Anim();
|
|
|
|
if ( r_loadAnimB.GetBool() ) {
|
|
idStr animbName = va( PREGENERATED_BASEDIR "/animb/%s", name );
|
|
animbName.StripFileExtension();
|
|
animbName = animbName + ".animb";
|
|
|
|
loaded = anim->LoadAnimBinary( animbName );
|
|
}
|
|
if ( !loaded ) {
|
|
if ( !anim->LoadAnim( filename ) ) {
|
|
gameLocal.Warning( "Couldn't load anim: '%s'", filename.c_str() );
|
|
delete anim;
|
|
anim = NULL;
|
|
}
|
|
}
|
|
|
|
if ( r_writeAnimB.GetBool() && anim ) {
|
|
// Write binary file
|
|
idStr fullPath, relativePath;
|
|
relativePath = va( PREGENERATED_BASEDIR "/animb/%s", name );
|
|
|
|
anim->WriteAnimBinary( relativePath );
|
|
}
|
|
|
|
animations.Set( filename, anim );
|
|
}
|
|
|
|
return anim;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimManager::ReloadAnims
|
|
================
|
|
*/
|
|
void idAnimManager::ReloadAnims( void ) {
|
|
int i;
|
|
idMD5Anim **animptr;
|
|
|
|
for ( i = 0; i < animations.Num(); i++ ) {
|
|
animptr = animations.GetIndex( i );
|
|
if ( animptr && *animptr ) {
|
|
( *animptr )->Reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimManager::JointIndex
|
|
================
|
|
*/
|
|
int idAnimManager::JointIndex( const char *name ) {
|
|
int i, hash;
|
|
|
|
hash = jointnamesHash.GenerateKey( name );
|
|
for ( i = jointnamesHash.GetFirst( hash ); i != -1; i = jointnamesHash.GetNext( i ) ) {
|
|
if ( jointnames[i].Cmp( name ) == 0 ) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
i = jointnames.Append( name );
|
|
jointnamesHash.Add( hash, i );
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimManager::JointName
|
|
================
|
|
*/
|
|
const char *idAnimManager::JointName( int index ) const {
|
|
return jointnames[ index ];
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimManager::ListAnims
|
|
================
|
|
*/
|
|
void idAnimManager::ListAnims( void ) const {
|
|
int i;
|
|
idMD5Anim* const* animptr;
|
|
idMD5Anim* anim;
|
|
size_t size;
|
|
size_t s;
|
|
size_t namesize;
|
|
int num;
|
|
|
|
num = 0;
|
|
size = 0;
|
|
for ( i = 0; i < animations.Num(); i++ ) {
|
|
animptr = animations.GetIndex( i );
|
|
if ( animptr && *animptr ) {
|
|
anim = *animptr;
|
|
s = anim->Size();
|
|
gameLocal.Printf( "%8d bytes : %2d refs : %s\n", s, anim->NumRefs(), anim->Name() );
|
|
size += s;
|
|
num++;
|
|
}
|
|
}
|
|
|
|
namesize = jointnames.Size() + jointnamesHash.Size();
|
|
for( i = 0; i < jointnames.Num(); i++ ) {
|
|
namesize += jointnames[ i ].Size();
|
|
}
|
|
|
|
gameLocal.Printf( "\n%d memory used in %d anims\n", size, num );
|
|
gameLocal.Printf( "%d memory used in %d joint names\n", namesize, jointnames.Num() );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAnimManager::FlushUnusedAnims
|
|
================
|
|
*/
|
|
void idAnimManager::FlushUnusedAnims( void ) {
|
|
int i;
|
|
idMD5Anim **animptr;
|
|
idList<idMD5Anim *> removeAnims;
|
|
|
|
for ( i = 0; i < animations.Num(); i++ ) {
|
|
animptr = animations.GetIndex( i );
|
|
if ( animptr && *animptr ) {
|
|
if ( ( *animptr )->NumRefs() <= 0 ) {
|
|
removeAnims.Append( *animptr );
|
|
}
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < removeAnims.Num(); i++ ) {
|
|
animations.Remove( removeAnims[ i ]->Name() );
|
|
delete removeAnims[ i ];
|
|
}
|
|
}
|