2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../Game_local.h"
34 bool idAnimManager::forceExport = false;
36 /***********************************************************************
40 ***********************************************************************/
47 idMD5Anim::idMD5Anim() {
61 idMD5Anim::~idMD5Anim() {
70 void idMD5Anim::Free( void ) {
81 componentFrames.Clear();
89 int idMD5Anim::NumFrames( void ) const {
98 int idMD5Anim::NumJoints( void ) const {
107 int idMD5Anim::Length( void ) const {
112 =====================
113 idMD5Anim::TotalMovementDelta
114 =====================
116 const idVec3 &idMD5Anim::TotalMovementDelta( void ) const {
121 =====================
122 idMD5Anim::TotalMovementDelta
123 =====================
125 const char *idMD5Anim::Name( void ) const {
134 bool idMD5Anim::Reload( void ) {
140 return LoadAnim( filename );
148 size_t idMD5Anim::Allocated( void ) const {
149 size_t size = bounds.Allocated() + jointInfo.Allocated() + componentFrames.Allocated() + name.Allocated();
158 bool idMD5Anim::LoadAnim( const char *filename ) {
160 idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
165 if ( !parser.LoadFile( filename ) ) {
173 parser.ExpectTokenString( MD5_VERSION_STRING );
174 version = parser.ParseInt();
175 if ( version != MD5_VERSION ) {
176 parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
179 // skip the commandline
180 parser.ExpectTokenString( "commandline" );
181 parser.ReadToken( &token );
184 parser.ExpectTokenString( "numFrames" );
185 numFrames = parser.ParseInt();
186 if ( numFrames <= 0 ) {
187 parser.Error( "Invalid number of frames: %d", numFrames );
191 parser.ExpectTokenString( "numJoints" );
192 numJoints = parser.ParseInt();
193 if ( numJoints <= 0 ) {
194 parser.Error( "Invalid number of joints: %d", numJoints );
198 parser.ExpectTokenString( "frameRate" );
199 frameRate = parser.ParseInt();
200 if ( frameRate < 0 ) {
201 parser.Error( "Invalid frame rate: %d", frameRate );
204 // parse number of animated components
205 parser.ExpectTokenString( "numAnimatedComponents" );
206 numAnimatedComponents = parser.ParseInt();
207 if ( ( numAnimatedComponents < 0 ) || ( numAnimatedComponents > numJoints * 6 ) ) {
208 parser.Error( "Invalid number of animated components: %d", numAnimatedComponents );
211 // parse the hierarchy
212 jointInfo.SetGranularity( 1 );
213 jointInfo.SetNum( numJoints );
214 parser.ExpectTokenString( "hierarchy" );
215 parser.ExpectTokenString( "{" );
216 for( i = 0; i < numJoints; i++ ) {
217 parser.ReadToken( &token );
218 jointInfo[ i ].nameIndex = animationLib.JointIndex( token );
221 jointInfo[ i ].parentNum = parser.ParseInt();
222 if ( jointInfo[ i ].parentNum >= i ) {
223 parser.Error( "Invalid parent num: %d", jointInfo[ i ].parentNum );
226 if ( ( i != 0 ) && ( jointInfo[ i ].parentNum < 0 ) ) {
227 parser.Error( "Animations may have only one root joint" );
231 jointInfo[ i ].animBits = parser.ParseInt();
232 if ( jointInfo[ i ].animBits & ~63 ) {
233 parser.Error( "Invalid anim bits: %d", jointInfo[ i ].animBits );
236 // parse first component
237 jointInfo[ i ].firstComponent = parser.ParseInt();
238 if ( ( numAnimatedComponents > 0 ) && ( ( jointInfo[ i ].firstComponent < 0 ) || ( jointInfo[ i ].firstComponent >= numAnimatedComponents ) ) ) {
239 parser.Error( "Invalid first component: %d", jointInfo[ i ].firstComponent );
243 parser.ExpectTokenString( "}" );
246 parser.ExpectTokenString( "bounds" );
247 parser.ExpectTokenString( "{" );
248 bounds.SetGranularity( 1 );
249 bounds.SetNum( numFrames );
250 for( i = 0; i < numFrames; i++ ) {
251 parser.Parse1DMatrix( 3, bounds[ i ][ 0 ].ToFloatPtr() );
252 parser.Parse1DMatrix( 3, bounds[ i ][ 1 ].ToFloatPtr() );
254 parser.ExpectTokenString( "}" );
257 baseFrame.SetGranularity( 1 );
258 baseFrame.SetNum( numJoints );
259 parser.ExpectTokenString( "baseframe" );
260 parser.ExpectTokenString( "{" );
261 for( i = 0; i < numJoints; i++ ) {
263 parser.Parse1DMatrix( 3, baseFrame[ i ].t.ToFloatPtr() );
264 parser.Parse1DMatrix( 3, q.ToFloatPtr() );//baseFrame[ i ].q.ToFloatPtr() );
265 baseFrame[ i ].q = q.ToQuat();//.w = baseFrame[ i ].q.CalcW();
267 parser.ExpectTokenString( "}" );
270 componentFrames.SetGranularity( 1 );
271 componentFrames.SetNum( numAnimatedComponents * numFrames );
273 float *componentPtr = componentFrames.Ptr();
274 for( i = 0; i < numFrames; i++ ) {
275 parser.ExpectTokenString( "frame" );
276 num = parser.ParseInt();
278 parser.Error( "Expected frame number %d", i );
280 parser.ExpectTokenString( "{" );
282 for( j = 0; j < numAnimatedComponents; j++, componentPtr++ ) {
283 *componentPtr = parser.ParseFloat();
286 parser.ExpectTokenString( "}" );
289 // get total move delta
290 if ( !numAnimatedComponents ) {
293 componentPtr = &componentFrames[ jointInfo[ 0 ].firstComponent ];
294 if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
295 for( i = 0; i < numFrames; i++ ) {
296 componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.x;
298 totaldelta.x = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
303 if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
304 for( i = 0; i < numFrames; i++ ) {
305 componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.y;
307 totaldelta.y = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
312 if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
313 for( i = 0; i < numFrames; i++ ) {
314 componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.z;
316 totaldelta.z = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
321 baseFrame[ 0 ].t.Zero();
323 // we don't count last frame because it would cause a 1 frame pause at the end
324 animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate;
332 idMD5Anim::IncreaseRefs
335 void idMD5Anim::IncreaseRefs( void ) const {
341 idMD5Anim::DecreaseRefs
344 void idMD5Anim::DecreaseRefs( void ) const {
353 int idMD5Anim::NumRefs( void ) const {
359 idMD5Anim::GetFrameBlend
362 void idMD5Anim::GetFrameBlend( int framenum, frameBlend_t &frame ) const {
363 frame.cycleCount = 0;
364 frame.backlerp = 0.0f;
365 frame.frontlerp = 1.0f;
367 // frame 1 is first frame
369 if ( framenum < 0 ) {
371 } else if ( framenum >= numFrames ) {
372 framenum = numFrames - 1;
375 frame.frame1 = framenum;
376 frame.frame2 = framenum;
381 idMD5Anim::ConvertTimeToFrame
384 void idMD5Anim::ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const {
388 if ( numFrames <= 1 ) {
391 frame.backlerp = 0.0f;
392 frame.frontlerp = 1.0f;
393 frame.cycleCount = 0;
400 frame.backlerp = 0.0f;
401 frame.frontlerp = 1.0f;
402 frame.cycleCount = 0;
406 frameTime = time * frameRate;
407 frameNum = frameTime / 1000;
408 frame.cycleCount = frameNum / ( numFrames - 1 );
410 if ( ( cyclecount > 0 ) && ( frame.cycleCount >= cyclecount ) ) {
411 frame.cycleCount = cyclecount - 1;
412 frame.frame1 = numFrames - 1;
413 frame.frame2 = frame.frame1;
414 frame.backlerp = 0.0f;
415 frame.frontlerp = 1.0f;
419 frame.frame1 = frameNum % ( numFrames - 1 );
420 frame.frame2 = frame.frame1 + 1;
421 if ( frame.frame2 >= numFrames ) {
425 frame.backlerp = ( frameTime % 1000 ) * 0.001f;
426 frame.frontlerp = 1.0f - frame.backlerp;
434 void idMD5Anim::GetOrigin( idVec3 &offset, int time, int cyclecount ) const {
437 offset = baseFrame[ 0 ].t;
438 if ( !( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) ) {
439 // just use the baseframe
443 ConvertTimeToFrame( time, cyclecount, frame );
445 const float *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
446 const float *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
448 if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
449 offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
454 if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
455 offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
460 if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
461 offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
464 if ( frame.cycleCount ) {
465 offset += totaldelta * ( float )frame.cycleCount;
471 idMD5Anim::GetOriginRotation
474 void idMD5Anim::GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const {
478 animBits = jointInfo[ 0 ].animBits;
479 if ( !( animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) ) ) {
480 // just use the baseframe
481 rotation = baseFrame[ 0 ].q;
485 ConvertTimeToFrame( time, cyclecount, frame );
487 const float *jointframe1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
488 const float *jointframe2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
490 if ( animBits & ANIM_TX ) {
495 if ( animBits & ANIM_TY ) {
500 if ( animBits & ANIM_TZ ) {
508 switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
510 q1.x = jointframe1[0];
511 q2.x = jointframe2[0];
512 q1.y = baseFrame[ 0 ].q.y;
514 q1.z = baseFrame[ 0 ].q.z;
520 q1.y = jointframe1[0];
521 q2.y = jointframe2[0];
522 q1.x = baseFrame[ 0 ].q.x;
524 q1.z = baseFrame[ 0 ].q.z;
530 q1.z = jointframe1[0];
531 q2.z = jointframe2[0];
532 q1.x = baseFrame[ 0 ].q.x;
534 q1.y = baseFrame[ 0 ].q.y;
539 case ANIM_QX|ANIM_QY:
540 q1.x = jointframe1[0];
541 q1.y = jointframe1[1];
542 q2.x = jointframe2[0];
543 q2.y = jointframe2[1];
544 q1.z = baseFrame[ 0 ].q.z;
549 case ANIM_QX|ANIM_QZ:
550 q1.x = jointframe1[0];
551 q1.z = jointframe1[1];
552 q2.x = jointframe2[0];
553 q2.z = jointframe2[1];
554 q1.y = baseFrame[ 0 ].q.y;
559 case ANIM_QY|ANIM_QZ:
560 q1.y = jointframe1[0];
561 q1.z = jointframe1[1];
562 q2.y = jointframe2[0];
563 q2.z = jointframe2[1];
564 q1.x = baseFrame[ 0 ].q.x;
569 case ANIM_QX|ANIM_QY|ANIM_QZ:
570 q1.x = jointframe1[0];
571 q1.y = jointframe1[1];
572 q1.z = jointframe1[2];
573 q2.x = jointframe2[0];
574 q2.y = jointframe2[1];
575 q2.z = jointframe2[2];
581 rotation.Slerp( q1, q2, frame.backlerp );
589 void idMD5Anim::GetBounds( idBounds &bnds, int time, int cyclecount ) const {
593 ConvertTimeToFrame( time, cyclecount, frame );
595 bnds = bounds[ frame.frame1 ];
596 bnds.AddBounds( bounds[ frame.frame2 ] );
599 offset = baseFrame[ 0 ].t;
600 if ( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) {
601 const float *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
602 const float *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
604 if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
605 offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
610 if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
611 offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
616 if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
617 offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
627 idMD5Anim::GetInterpolatedFrame
630 void idMD5Anim::GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const {
631 int i, numLerpJoints;
634 const float *jointframe1;
635 const float *jointframe2;
636 const jointAnimInfo_t *infoPtr;
638 idJointQuat *blendJoints;
639 idJointQuat *jointPtr;
640 idJointQuat *blendPtr;
643 // copy the baseframe
644 SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) );
646 if ( !numAnimatedComponents ) {
647 // just use the base frame
651 blendJoints = (idJointQuat *)_alloca16( baseFrame.Num() * sizeof( blendPtr[ 0 ] ) );
652 lerpIndex = (int *)_alloca16( baseFrame.Num() * sizeof( lerpIndex[ 0 ] ) );
655 frame1 = &componentFrames[ frame.frame1 * numAnimatedComponents ];
656 frame2 = &componentFrames[ frame.frame2 * numAnimatedComponents ];
658 for ( i = 0; i < numIndexes; i++ ) {
660 jointPtr = &joints[j];
661 blendPtr = &blendJoints[j];
662 infoPtr = &jointInfo[j];
664 animBits = infoPtr->animBits;
667 lerpIndex[numLerpJoints++] = j;
669 jointframe1 = frame1 + infoPtr->firstComponent;
670 jointframe2 = frame2 + infoPtr->firstComponent;
672 switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
674 blendPtr->t = jointPtr->t;
677 jointPtr->t.x = jointframe1[0];
678 blendPtr->t.x = jointframe2[0];
679 blendPtr->t.y = jointPtr->t.y;
680 blendPtr->t.z = jointPtr->t.z;
685 jointPtr->t.y = jointframe1[0];
686 blendPtr->t.y = jointframe2[0];
687 blendPtr->t.x = jointPtr->t.x;
688 blendPtr->t.z = jointPtr->t.z;
693 jointPtr->t.z = jointframe1[0];
694 blendPtr->t.z = jointframe2[0];
695 blendPtr->t.x = jointPtr->t.x;
696 blendPtr->t.y = jointPtr->t.y;
700 case ANIM_TX|ANIM_TY:
701 jointPtr->t.x = jointframe1[0];
702 jointPtr->t.y = jointframe1[1];
703 blendPtr->t.x = jointframe2[0];
704 blendPtr->t.y = jointframe2[1];
705 blendPtr->t.z = jointPtr->t.z;
709 case ANIM_TX|ANIM_TZ:
710 jointPtr->t.x = jointframe1[0];
711 jointPtr->t.z = jointframe1[1];
712 blendPtr->t.x = jointframe2[0];
713 blendPtr->t.z = jointframe2[1];
714 blendPtr->t.y = jointPtr->t.y;
718 case ANIM_TY|ANIM_TZ:
719 jointPtr->t.y = jointframe1[0];
720 jointPtr->t.z = jointframe1[1];
721 blendPtr->t.y = jointframe2[0];
722 blendPtr->t.z = jointframe2[1];
723 blendPtr->t.x = jointPtr->t.x;
727 case ANIM_TX|ANIM_TY|ANIM_TZ:
728 jointPtr->t.x = jointframe1[0];
729 jointPtr->t.y = jointframe1[1];
730 jointPtr->t.z = jointframe1[2];
731 blendPtr->t.x = jointframe2[0];
732 blendPtr->t.y = jointframe2[1];
733 blendPtr->t.z = jointframe2[2];
739 switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
741 blendPtr->q = jointPtr->q;
744 jointPtr->q.x = jointframe1[0];
745 blendPtr->q.x = jointframe2[0];
746 blendPtr->q.y = jointPtr->q.y;
747 blendPtr->q.z = jointPtr->q.z;
748 jointPtr->q.w = jointPtr->q.CalcW();
749 blendPtr->q.w = blendPtr->q.CalcW();
752 jointPtr->q.y = jointframe1[0];
753 blendPtr->q.y = jointframe2[0];
754 blendPtr->q.x = jointPtr->q.x;
755 blendPtr->q.z = jointPtr->q.z;
756 jointPtr->q.w = jointPtr->q.CalcW();
757 blendPtr->q.w = blendPtr->q.CalcW();
760 jointPtr->q.z = jointframe1[0];
761 blendPtr->q.z = jointframe2[0];
762 blendPtr->q.x = jointPtr->q.x;
763 blendPtr->q.y = jointPtr->q.y;
764 jointPtr->q.w = jointPtr->q.CalcW();
765 blendPtr->q.w = blendPtr->q.CalcW();
767 case ANIM_QX|ANIM_QY:
768 jointPtr->q.x = jointframe1[0];
769 jointPtr->q.y = jointframe1[1];
770 blendPtr->q.x = jointframe2[0];
771 blendPtr->q.y = jointframe2[1];
772 blendPtr->q.z = jointPtr->q.z;
773 jointPtr->q.w = jointPtr->q.CalcW();
774 blendPtr->q.w = blendPtr->q.CalcW();
776 case ANIM_QX|ANIM_QZ:
777 jointPtr->q.x = jointframe1[0];
778 jointPtr->q.z = jointframe1[1];
779 blendPtr->q.x = jointframe2[0];
780 blendPtr->q.z = jointframe2[1];
781 blendPtr->q.y = jointPtr->q.y;
782 jointPtr->q.w = jointPtr->q.CalcW();
783 blendPtr->q.w = blendPtr->q.CalcW();
785 case ANIM_QY|ANIM_QZ:
786 jointPtr->q.y = jointframe1[0];
787 jointPtr->q.z = jointframe1[1];
788 blendPtr->q.y = jointframe2[0];
789 blendPtr->q.z = jointframe2[1];
790 blendPtr->q.x = jointPtr->q.x;
791 jointPtr->q.w = jointPtr->q.CalcW();
792 blendPtr->q.w = blendPtr->q.CalcW();
794 case ANIM_QX|ANIM_QY|ANIM_QZ:
795 jointPtr->q.x = jointframe1[0];
796 jointPtr->q.y = jointframe1[1];
797 jointPtr->q.z = jointframe1[2];
798 blendPtr->q.x = jointframe2[0];
799 blendPtr->q.y = jointframe2[1];
800 blendPtr->q.z = jointframe2[2];
801 jointPtr->q.w = jointPtr->q.CalcW();
802 blendPtr->q.w = blendPtr->q.CalcW();
808 SIMDProcessor->BlendJoints( joints, blendJoints, frame.backlerp, lerpIndex, numLerpJoints );
810 if ( frame.cycleCount ) {
811 joints[ 0 ].t += totaldelta * ( float )frame.cycleCount;
817 idMD5Anim::GetSingleFrame
820 void idMD5Anim::GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const {
823 const float *jointframe;
825 idJointQuat *jointPtr;
826 const jointAnimInfo_t *infoPtr;
828 // copy the baseframe
829 SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) );
831 if ( ( framenum == 0 ) || !numAnimatedComponents ) {
832 // just use the base frame
836 frame = &componentFrames[ framenum * numAnimatedComponents ];
838 for ( i = 0; i < numIndexes; i++ ) {
840 jointPtr = &joints[j];
841 infoPtr = &jointInfo[j];
843 animBits = infoPtr->animBits;
846 jointframe = frame + infoPtr->firstComponent;
848 if ( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
850 if ( animBits & ANIM_TX ) {
851 jointPtr->t.x = *jointframe++;
854 if ( animBits & ANIM_TY ) {
855 jointPtr->t.y = *jointframe++;
858 if ( animBits & ANIM_TZ ) {
859 jointPtr->t.z = *jointframe++;
863 if ( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
865 if ( animBits & ANIM_QX ) {
866 jointPtr->q.x = *jointframe++;
869 if ( animBits & ANIM_QY ) {
870 jointPtr->q.y = *jointframe++;
873 if ( animBits & ANIM_QZ ) {
874 jointPtr->q.z = *jointframe;
877 jointPtr->q.w = jointPtr->q.CalcW();
885 idMD5Anim::CheckModelHierarchy
888 void idMD5Anim::CheckModelHierarchy( const idRenderModel *model ) const {
893 if ( jointInfo.Num() != model->NumJoints() ) {
894 gameLocal.Error( "Model '%s' has different # of joints than anim '%s'", model->Name(), name.c_str() );
897 const idMD5Joint *modelJoints = model->GetJoints();
898 for( i = 0; i < jointInfo.Num(); i++ ) {
899 jointNum = jointInfo[ i ].nameIndex;
900 if ( modelJoints[ i ].name != animationLib.JointName( jointNum ) ) {
901 gameLocal.Error( "Model '%s''s joint names don't match anim '%s''s", model->Name(), name.c_str() );
903 if ( modelJoints[ i ].parent ) {
904 parent = modelJoints[ i ].parent - modelJoints;
908 if ( parent != jointInfo[ i ].parentNum ) {
909 gameLocal.Error( "Model '%s' has different joint hierarchy than anim '%s'", model->Name(), name.c_str() );
914 /***********************************************************************
918 ***********************************************************************/
922 idAnimManager::idAnimManager
925 idAnimManager::idAnimManager() {
930 idAnimManager::~idAnimManager
933 idAnimManager::~idAnimManager() {
939 idAnimManager::Shutdown
942 void idAnimManager::Shutdown( void ) {
943 animations.DeleteContents();
945 jointnamesHash.Free();
950 idAnimManager::GetAnim
953 idMD5Anim *idAnimManager::GetAnim( const char *name ) {
954 idMD5Anim **animptrptr;
957 // see if it has been asked for before
959 if ( animations.Get( name, &animptrptr ) ) {
963 idStr filename = name;
965 filename.ExtractFileExtension( extension );
966 if ( extension != MD5_ANIM_EXT ) {
970 anim = new idMD5Anim();
971 if ( !anim->LoadAnim( filename ) ) {
972 gameLocal.Warning( "Couldn't load anim: '%s'", filename.c_str() );
976 animations.Set( filename, anim );
984 idAnimManager::ReloadAnims
987 void idAnimManager::ReloadAnims( void ) {
991 for( i = 0; i < animations.Num(); i++ ) {
992 animptr = animations.GetIndex( i );
993 if ( animptr && *animptr ) {
994 ( *animptr )->Reload();
1001 idAnimManager::JointIndex
1004 int idAnimManager::JointIndex( const char *name ) {
1007 hash = jointnamesHash.GenerateKey( name );
1008 for ( i = jointnamesHash.First( hash ); i != -1; i = jointnamesHash.Next( i ) ) {
1009 if ( jointnames[i].Cmp( name ) == 0 ) {
1014 i = jointnames.Append( name );
1015 jointnamesHash.Add( hash, i );
1021 idAnimManager::JointName
1024 const char *idAnimManager::JointName( int index ) const {
1025 return jointnames[ index ];
1030 idAnimManager::ListAnims
1033 void idAnimManager::ListAnims( void ) const {
1035 idMD5Anim **animptr;
1044 for( i = 0; i < animations.Num(); i++ ) {
1045 animptr = animations.GetIndex( i );
1046 if ( animptr && *animptr ) {
1049 gameLocal.Printf( "%8d bytes : %2d refs : %s\n", s, anim->NumRefs(), anim->Name() );
1055 namesize = jointnames.Size() + jointnamesHash.Size();
1056 for( i = 0; i < jointnames.Num(); i++ ) {
1057 namesize += jointnames[ i ].Size();
1060 gameLocal.Printf( "\n%d memory used in %d anims\n", size, num );
1061 gameLocal.Printf( "%d memory used in %d joint names\n", namesize, jointnames.Num() );
1066 idAnimManager::FlushUnusedAnims
1069 void idAnimManager::FlushUnusedAnims( void ) {
1071 idMD5Anim **animptr;
1072 idList<idMD5Anim *> removeAnims;
1074 for( i = 0; i < animations.Num(); i++ ) {
1075 animptr = animations.GetIndex( i );
1076 if ( animptr && *animptr ) {
1077 if ( ( *animptr )->NumRefs() <= 0 ) {
1078 removeAnims.Append( *animptr );
1083 for( i = 0; i < removeAnims.Num(); i++ ) {
1084 animations.Remove( removeAnims[ i ]->Name() );
1085 delete removeAnims[ i ];