]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/anim/Anim.cpp
hello world
[icculus/iodoom3.git] / neo / game / anim / Anim.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
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.
13
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.
18
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/>.
21
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.
23
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.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../Game_local.h"
33
34 bool idAnimManager::forceExport = false;
35
36 /***********************************************************************
37
38         idMD5Anim
39
40 ***********************************************************************/
41
42 /*
43 ====================
44 idMD5Anim::idMD5Anim
45 ====================
46 */
47 idMD5Anim::idMD5Anim() {
48         ref_count       = 0;
49         numFrames       = 0;
50         numJoints       = 0;
51         frameRate       = 24;
52         animLength      = 0;
53         totaldelta.Zero();
54 }
55
56 /*
57 ====================
58 idMD5Anim::idMD5Anim
59 ====================
60 */
61 idMD5Anim::~idMD5Anim() {
62         Free();
63 }
64
65 /*
66 ====================
67 idMD5Anim::Free
68 ====================
69 */
70 void idMD5Anim::Free( void ) {
71         numFrames       = 0;
72         numJoints       = 0;
73         frameRate       = 24;
74         animLength      = 0;
75         name            = "";
76
77         totaldelta.Zero();
78
79         jointInfo.Clear();
80         bounds.Clear();
81         componentFrames.Clear();
82 }
83
84 /*
85 ====================
86 idMD5Anim::NumFrames
87 ====================
88 */
89 int     idMD5Anim::NumFrames( void ) const {
90         return numFrames;
91 }
92
93 /*
94 ====================
95 idMD5Anim::NumJoints
96 ====================
97 */
98 int     idMD5Anim::NumJoints( void ) const {
99         return numJoints;
100 }
101
102 /*
103 ====================
104 idMD5Anim::Length
105 ====================
106 */
107 int idMD5Anim::Length( void ) const {
108         return animLength;
109 }
110
111 /*
112 =====================
113 idMD5Anim::TotalMovementDelta
114 =====================
115 */
116 const idVec3 &idMD5Anim::TotalMovementDelta( void ) const {
117         return totaldelta;
118 }
119
120 /*
121 =====================
122 idMD5Anim::TotalMovementDelta
123 =====================
124 */
125 const char *idMD5Anim::Name( void ) const {
126         return name;
127 }
128
129 /*
130 ====================
131 idMD5Anim::Reload
132 ====================
133 */
134 bool idMD5Anim::Reload( void ) {
135         idStr filename;
136
137         filename = name;
138         Free();
139
140         return LoadAnim( filename );
141 }
142
143 /*
144 ====================
145 idMD5Anim::Allocated
146 ====================
147 */
148 size_t idMD5Anim::Allocated( void ) const {
149         size_t  size = bounds.Allocated() + jointInfo.Allocated() + componentFrames.Allocated() + name.Allocated();
150         return size;
151 }
152
153 /*
154 ====================
155 idMD5Anim::LoadAnim
156 ====================
157 */
158 bool idMD5Anim::LoadAnim( const char *filename ) {
159         int             version;
160         idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
161         idToken token;
162         int             i, j;
163         int             num;
164
165         if ( !parser.LoadFile( filename ) ) {
166                 return false;
167         }
168
169         Free();
170
171         name = filename;
172
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 );
177         }
178
179         // skip the commandline
180         parser.ExpectTokenString( "commandline" );
181         parser.ReadToken( &token );
182
183         // parse num frames
184         parser.ExpectTokenString( "numFrames" );
185         numFrames = parser.ParseInt();
186         if ( numFrames <= 0 ) {
187                 parser.Error( "Invalid number of frames: %d", numFrames );
188         }
189
190         // parse num joints
191         parser.ExpectTokenString( "numJoints" );
192         numJoints = parser.ParseInt();
193         if ( numJoints <= 0 ) {
194                 parser.Error( "Invalid number of joints: %d", numJoints );
195         }
196
197         // parse frame rate
198         parser.ExpectTokenString( "frameRate" );
199         frameRate = parser.ParseInt();
200         if ( frameRate < 0 ) {
201                 parser.Error( "Invalid frame rate: %d", frameRate );
202         }
203
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 );
209         }
210
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 );
219                 
220                 // parse parent num
221                 jointInfo[ i ].parentNum = parser.ParseInt();
222                 if ( jointInfo[ i ].parentNum >= i ) {
223                         parser.Error( "Invalid parent num: %d", jointInfo[ i ].parentNum );
224                 }
225
226                 if ( ( i != 0 ) && ( jointInfo[ i ].parentNum < 0 ) ) {
227                         parser.Error( "Animations may have only one root joint" );
228                 }
229
230                 // parse anim bits
231                 jointInfo[ i ].animBits = parser.ParseInt();
232                 if ( jointInfo[ i ].animBits & ~63 ) {
233                         parser.Error( "Invalid anim bits: %d", jointInfo[ i ].animBits );
234                 }
235
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 );
240                 }
241         }
242
243         parser.ExpectTokenString( "}" );
244
245         // parse bounds
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() );
253         }
254         parser.ExpectTokenString( "}" );
255
256         // parse base frame
257         baseFrame.SetGranularity( 1 );
258         baseFrame.SetNum( numJoints );
259         parser.ExpectTokenString( "baseframe" );
260         parser.ExpectTokenString( "{" );
261         for( i = 0; i < numJoints; i++ ) {
262                 idCQuat q;
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();
266         }
267         parser.ExpectTokenString( "}" );
268
269         // parse frames
270         componentFrames.SetGranularity( 1 );
271         componentFrames.SetNum( numAnimatedComponents * numFrames );
272
273         float *componentPtr = componentFrames.Ptr();
274         for( i = 0; i < numFrames; i++ ) {
275                 parser.ExpectTokenString( "frame" );
276                 num = parser.ParseInt();
277                 if ( num != i ) {
278                         parser.Error( "Expected frame number %d", i );
279                 }
280                 parser.ExpectTokenString( "{" );
281                 
282                 for( j = 0; j < numAnimatedComponents; j++, componentPtr++ ) {
283                         *componentPtr = parser.ParseFloat();
284                 }
285
286                 parser.ExpectTokenString( "}" );
287         }
288
289         // get total move delta
290         if ( !numAnimatedComponents ) {
291                 totaldelta.Zero();
292         } else {
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;
297                         }
298                         totaldelta.x = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
299                         componentPtr++;
300                 } else {
301                         totaldelta.x = 0.0f;
302                 }
303                 if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
304                         for( i = 0; i < numFrames; i++ ) {
305                                 componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.y;
306                         }
307                         totaldelta.y = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
308                         componentPtr++;
309                 } else {
310                         totaldelta.y = 0.0f;
311                 }
312                 if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
313                         for( i = 0; i < numFrames; i++ ) {
314                                 componentPtr[ numAnimatedComponents * i ] -= baseFrame[ 0 ].t.z;
315                         }
316                         totaldelta.z = componentPtr[ numAnimatedComponents * ( numFrames - 1 ) ];
317                 } else {
318                         totaldelta.z = 0.0f;
319                 }
320         }
321         baseFrame[ 0 ].t.Zero();
322
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;
325
326         // done
327         return true;
328 }
329
330 /*
331 ====================
332 idMD5Anim::IncreaseRefs
333 ====================
334 */
335 void idMD5Anim::IncreaseRefs( void ) const {
336         ref_count++;
337 }
338
339 /*
340 ====================
341 idMD5Anim::DecreaseRefs
342 ====================
343 */
344 void idMD5Anim::DecreaseRefs( void ) const {
345         ref_count--;
346 }
347
348 /*
349 ====================
350 idMD5Anim::NumRefs
351 ====================
352 */
353 int idMD5Anim::NumRefs( void ) const {
354         return ref_count;
355 }
356
357 /*
358 ====================
359 idMD5Anim::GetFrameBlend
360 ====================
361 */
362 void idMD5Anim::GetFrameBlend( int framenum, frameBlend_t &frame ) const {
363         frame.cycleCount        = 0;
364         frame.backlerp          = 0.0f;
365         frame.frontlerp         = 1.0f;
366
367         // frame 1 is first frame
368         framenum--;
369         if ( framenum < 0 ) {
370                 framenum = 0;
371         } else if ( framenum >= numFrames ) {
372                 framenum = numFrames - 1;
373         }
374
375         frame.frame1 = framenum;
376         frame.frame2 = framenum;
377 }
378
379 /*
380 ====================
381 idMD5Anim::ConvertTimeToFrame
382 ====================
383 */
384 void idMD5Anim::ConvertTimeToFrame( int time, int cyclecount, frameBlend_t &frame ) const {
385         int frameTime;
386         int frameNum;
387
388         if ( numFrames <= 1 ) {
389                 frame.frame1            = 0;
390                 frame.frame2            = 0;
391                 frame.backlerp          = 0.0f;
392                 frame.frontlerp         = 1.0f;
393                 frame.cycleCount        = 0;
394                 return;
395         }
396
397         if ( time <= 0 ) {
398                 frame.frame1            = 0;
399                 frame.frame2            = 1;
400                 frame.backlerp          = 0.0f;
401                 frame.frontlerp         = 1.0f;
402                 frame.cycleCount        = 0;
403                 return;
404         }
405         
406         frameTime                       = time * frameRate;
407         frameNum                        = frameTime / 1000;
408         frame.cycleCount        = frameNum / ( numFrames - 1 );
409
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;
416                 return;
417         }
418         
419         frame.frame1 = frameNum % ( numFrames - 1 );
420         frame.frame2 = frame.frame1 + 1;
421         if ( frame.frame2 >= numFrames ) {
422                 frame.frame2 = 0;
423         }
424
425         frame.backlerp  = ( frameTime % 1000 ) * 0.001f;
426         frame.frontlerp = 1.0f - frame.backlerp;
427 }
428
429 /*
430 ====================
431 idMD5Anim::GetOrigin
432 ====================
433 */
434 void idMD5Anim::GetOrigin( idVec3 &offset, int time, int cyclecount ) const {
435         frameBlend_t frame;
436
437         offset = baseFrame[ 0 ].t;
438         if ( !( jointInfo[ 0 ].animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) ) {
439                 // just use the baseframe               
440                 return;
441         }
442
443         ConvertTimeToFrame( time, cyclecount, frame );
444
445         const float *componentPtr1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
446         const float *componentPtr2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
447
448         if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
449                 offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
450                 componentPtr1++;
451                 componentPtr2++;
452         }
453
454         if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
455                 offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
456                 componentPtr1++;
457                 componentPtr2++;
458         }
459
460         if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
461                 offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
462         }
463
464         if ( frame.cycleCount ) {
465                 offset += totaldelta * ( float )frame.cycleCount;
466         }
467 }
468
469 /*
470 ====================
471 idMD5Anim::GetOriginRotation
472 ====================
473 */
474 void idMD5Anim::GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const {
475         frameBlend_t    frame;
476         int                             animBits;
477         
478         animBits = jointInfo[ 0 ].animBits;
479         if ( !( animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) ) ) {
480                 // just use the baseframe               
481                 rotation = baseFrame[ 0 ].q;
482                 return;
483         }
484
485         ConvertTimeToFrame( time, cyclecount, frame );
486
487         const float     *jointframe1 = &componentFrames[ numAnimatedComponents * frame.frame1 + jointInfo[ 0 ].firstComponent ];
488         const float     *jointframe2 = &componentFrames[ numAnimatedComponents * frame.frame2 + jointInfo[ 0 ].firstComponent ];
489
490         if ( animBits & ANIM_TX ) {
491                 jointframe1++;
492                 jointframe2++;
493         }
494
495         if ( animBits & ANIM_TY ) {
496                 jointframe1++;
497                 jointframe2++;
498         }
499
500         if ( animBits & ANIM_TZ ) {
501                 jointframe1++;
502                 jointframe2++;
503         }
504
505         idQuat q1;
506         idQuat q2;
507
508         switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
509                 case ANIM_QX:
510                         q1.x = jointframe1[0];
511                         q2.x = jointframe2[0];
512                         q1.y = baseFrame[ 0 ].q.y;
513                         q2.y = q1.y;
514                         q1.z = baseFrame[ 0 ].q.z;
515                         q2.z = q1.z;
516                         q1.w = q1.CalcW();
517                         q2.w = q2.CalcW();
518                         break;
519                 case ANIM_QY:
520                         q1.y = jointframe1[0];
521                         q2.y = jointframe2[0];
522                         q1.x = baseFrame[ 0 ].q.x;
523                         q2.x = q1.x;
524                         q1.z = baseFrame[ 0 ].q.z;
525                         q2.z = q1.z;
526                         q1.w = q1.CalcW();
527                         q2.w = q2.CalcW();
528                         break;
529                 case ANIM_QZ:
530                         q1.z = jointframe1[0];
531                         q2.z = jointframe2[0];
532                         q1.x = baseFrame[ 0 ].q.x;
533                         q2.x = q1.x;
534                         q1.y = baseFrame[ 0 ].q.y;
535                         q2.y = q1.y;
536                         q1.w = q1.CalcW();
537                         q2.w = q2.CalcW();
538                         break;
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;
545                         q2.z = q1.z;
546                         q1.w = q1.CalcW();
547                         q2.w = q2.CalcW();
548                         break;
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;
555                         q2.y = q1.y;
556                         q1.w = q1.CalcW();
557                         q2.w = q2.CalcW();
558                         break;
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;
565                         q2.x = q1.x;
566                         q1.w = q1.CalcW();
567                         q2.w = q2.CalcW();
568                         break;
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];
576                         q1.w = q1.CalcW();
577                         q2.w = q2.CalcW();
578                         break;
579         }
580
581         rotation.Slerp( q1, q2, frame.backlerp );
582 }
583
584 /*
585 ====================
586 idMD5Anim::GetBounds
587 ====================
588 */
589 void idMD5Anim::GetBounds( idBounds &bnds, int time, int cyclecount ) const {
590         frameBlend_t    frame;
591         idVec3                  offset;
592
593         ConvertTimeToFrame( time, cyclecount, frame );
594
595         bnds = bounds[ frame.frame1 ];
596         bnds.AddBounds( bounds[ frame.frame2 ] );
597
598         // origin position
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 ];
603
604                 if ( jointInfo[ 0 ].animBits & ANIM_TX ) {
605                         offset.x = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
606                         componentPtr1++;
607                         componentPtr2++;
608                 }
609
610                 if ( jointInfo[ 0 ].animBits & ANIM_TY ) {
611                         offset.y = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
612                         componentPtr1++;
613                         componentPtr2++;
614                 }
615
616                 if ( jointInfo[ 0 ].animBits & ANIM_TZ ) {
617                         offset.z = *componentPtr1 * frame.frontlerp + *componentPtr2 * frame.backlerp;
618                 }
619         }
620
621         bnds[ 0 ] -= offset;
622         bnds[ 1 ] -= offset;
623 }
624
625 /*
626 ====================
627 idMD5Anim::GetInterpolatedFrame
628 ====================
629 */
630 void idMD5Anim::GetInterpolatedFrame( frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes ) const {
631         int                                             i, numLerpJoints;
632         const float                             *frame1;
633         const float                             *frame2;
634         const float                             *jointframe1;
635         const float                             *jointframe2;
636         const jointAnimInfo_t   *infoPtr;
637         int                                             animBits;
638         idJointQuat                             *blendJoints;
639         idJointQuat                             *jointPtr;
640         idJointQuat                             *blendPtr;
641         int                                             *lerpIndex;
642
643         // copy the baseframe
644         SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) );
645
646         if ( !numAnimatedComponents ) {
647                 // just use the base frame
648                 return;
649         }
650
651         blendJoints = (idJointQuat *)_alloca16( baseFrame.Num() * sizeof( blendPtr[ 0 ] ) );
652         lerpIndex = (int *)_alloca16( baseFrame.Num() * sizeof( lerpIndex[ 0 ] ) );
653         numLerpJoints = 0;
654
655         frame1 = &componentFrames[ frame.frame1 * numAnimatedComponents ];
656         frame2 = &componentFrames[ frame.frame2 * numAnimatedComponents ];
657
658         for ( i = 0; i < numIndexes; i++ ) {
659                 int j = index[i];
660                 jointPtr = &joints[j];
661                 blendPtr = &blendJoints[j];
662                 infoPtr = &jointInfo[j];
663
664                 animBits = infoPtr->animBits;
665                 if ( animBits ) {
666
667                         lerpIndex[numLerpJoints++] = j;
668
669                         jointframe1 = frame1 + infoPtr->firstComponent;
670                         jointframe2 = frame2 + infoPtr->firstComponent;
671
672                         switch( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
673                                 case 0:
674                                         blendPtr->t = jointPtr->t;
675                                         break;
676                                 case ANIM_TX:
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;
681                                         jointframe1++;
682                                         jointframe2++;
683                                         break;
684                                 case ANIM_TY:
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;
689                                         jointframe1++;
690                                         jointframe2++;
691                                         break;
692                                 case ANIM_TZ:
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;
697                                         jointframe1++;
698                                         jointframe2++;
699                                         break;
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;
706                                         jointframe1 += 2;
707                                         jointframe2 += 2;
708                                         break;
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;
715                                         jointframe1 += 2;
716                                         jointframe2 += 2;
717                                         break;
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;
724                                         jointframe1 += 2;
725                                         jointframe2 += 2;
726                                         break;
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];
734                                         jointframe1 += 3;
735                                         jointframe2 += 3;
736                                         break;
737                         }
738
739                         switch( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
740                                 case 0:
741                                         blendPtr->q = jointPtr->q;
742                                         break;
743                                 case ANIM_QX:
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();
750                                         break;
751                                 case ANIM_QY:
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();
758                                         break;
759                                 case ANIM_QZ:
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();
766                                         break;
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();
775                                         break;
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();
784                                         break;
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();
793                                         break;
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();
803                                         break;
804                         }
805                 }
806         }
807
808         SIMDProcessor->BlendJoints( joints, blendJoints, frame.backlerp, lerpIndex, numLerpJoints );
809
810         if ( frame.cycleCount ) {
811                 joints[ 0 ].t += totaldelta * ( float )frame.cycleCount;
812         }
813 }
814
815 /*
816 ====================
817 idMD5Anim::GetSingleFrame
818 ====================
819 */
820 void idMD5Anim::GetSingleFrame( int framenum, idJointQuat *joints, const int *index, int numIndexes ) const {
821         int                                             i;
822         const float                             *frame;
823         const float                             *jointframe;
824         int                                             animBits;
825         idJointQuat                             *jointPtr;
826         const jointAnimInfo_t   *infoPtr;
827
828         // copy the baseframe
829         SIMDProcessor->Memcpy( joints, baseFrame.Ptr(), baseFrame.Num() * sizeof( baseFrame[ 0 ] ) );
830
831         if ( ( framenum == 0 ) || !numAnimatedComponents ) {
832                 // just use the base frame
833                 return;
834         }
835
836         frame = &componentFrames[ framenum * numAnimatedComponents ];
837
838         for ( i = 0; i < numIndexes; i++ ) {
839                 int j = index[i];
840                 jointPtr = &joints[j];
841                 infoPtr = &jointInfo[j];
842
843                 animBits = infoPtr->animBits;
844                 if ( animBits ) {
845
846                         jointframe = frame + infoPtr->firstComponent;
847
848                         if ( animBits & (ANIM_TX|ANIM_TY|ANIM_TZ) ) {
849
850                                 if ( animBits & ANIM_TX ) {
851                                         jointPtr->t.x = *jointframe++;
852                                 }
853
854                                 if ( animBits & ANIM_TY ) {
855                                         jointPtr->t.y = *jointframe++;
856                                 }
857
858                                 if ( animBits & ANIM_TZ ) {
859                                         jointPtr->t.z = *jointframe++;
860                                 }
861                         }
862
863                         if ( animBits & (ANIM_QX|ANIM_QY|ANIM_QZ) ) {
864
865                                 if ( animBits & ANIM_QX ) {
866                                         jointPtr->q.x = *jointframe++;
867                                 }
868
869                                 if ( animBits & ANIM_QY ) {
870                                         jointPtr->q.y = *jointframe++;
871                                 }
872
873                                 if ( animBits & ANIM_QZ ) {
874                                         jointPtr->q.z = *jointframe;
875                                 }
876
877                                 jointPtr->q.w = jointPtr->q.CalcW();
878                         }
879                 }
880         }
881 }
882
883 /*
884 ====================
885 idMD5Anim::CheckModelHierarchy
886 ====================
887 */
888 void idMD5Anim::CheckModelHierarchy( const idRenderModel *model ) const {
889         int     i;
890         int     jointNum;
891         int     parent;
892
893         if ( jointInfo.Num() != model->NumJoints() ) {
894                 gameLocal.Error( "Model '%s' has different # of joints than anim '%s'", model->Name(), name.c_str() );
895         }
896
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() );
902                 }
903                 if ( modelJoints[ i ].parent ) {
904                         parent = modelJoints[ i ].parent - modelJoints;
905                 } else {
906                         parent = -1;
907                 }
908                 if ( parent != jointInfo[ i ].parentNum ) {
909                         gameLocal.Error( "Model '%s' has different joint hierarchy than anim '%s'", model->Name(), name.c_str() );
910                 }
911         }
912 }
913
914 /***********************************************************************
915
916         idAnimManager
917
918 ***********************************************************************/
919
920 /*
921 ====================
922 idAnimManager::idAnimManager
923 ====================
924 */
925 idAnimManager::idAnimManager() {
926 }
927
928 /*
929 ====================
930 idAnimManager::~idAnimManager
931 ====================
932 */
933 idAnimManager::~idAnimManager() {
934         Shutdown();
935 }
936
937 /*
938 ====================
939 idAnimManager::Shutdown
940 ====================
941 */
942 void idAnimManager::Shutdown( void ) {
943         animations.DeleteContents();
944         jointnames.Clear();
945         jointnamesHash.Free();
946 }
947
948 /*
949 ====================
950 idAnimManager::GetAnim
951 ====================
952 */
953 idMD5Anim *idAnimManager::GetAnim( const char *name ) {
954         idMD5Anim **animptrptr;
955         idMD5Anim *anim;
956
957         // see if it has been asked for before
958         animptrptr = NULL;
959         if ( animations.Get( name, &animptrptr ) ) {
960                 anim = *animptrptr;
961         } else {
962                 idStr extension;
963                 idStr filename = name;
964
965                 filename.ExtractFileExtension( extension );
966                 if ( extension != MD5_ANIM_EXT ) {
967                         return NULL;
968                 }
969
970                 anim = new idMD5Anim();
971                 if ( !anim->LoadAnim( filename ) ) {
972                         gameLocal.Warning( "Couldn't load anim: '%s'", filename.c_str() );
973                         delete anim;
974                         anim = NULL;
975                 }
976                 animations.Set( filename, anim );
977         }
978
979         return anim;
980 }
981
982 /*
983 ================
984 idAnimManager::ReloadAnims
985 ================
986 */
987 void idAnimManager::ReloadAnims( void ) {
988         int                     i;
989         idMD5Anim       **animptr;
990
991         for( i = 0; i < animations.Num(); i++ ) {
992                 animptr = animations.GetIndex( i );
993                 if ( animptr && *animptr ) {
994                         ( *animptr )->Reload();
995                 }
996         }
997 }
998
999 /*
1000 ================
1001 idAnimManager::JointIndex
1002 ================
1003 */
1004 int     idAnimManager::JointIndex( const char *name ) {
1005         int i, hash;
1006
1007         hash = jointnamesHash.GenerateKey( name );
1008         for ( i = jointnamesHash.First( hash ); i != -1; i = jointnamesHash.Next( i ) ) {
1009                 if ( jointnames[i].Cmp( name ) == 0 ) {
1010                         return i;
1011                 }
1012         }
1013
1014         i = jointnames.Append( name );
1015         jointnamesHash.Add( hash, i );
1016         return i;
1017 }
1018
1019 /*
1020 ================
1021 idAnimManager::JointName
1022 ================
1023 */
1024 const char *idAnimManager::JointName( int index ) const {
1025         return jointnames[ index ];
1026 }
1027
1028 /*
1029 ================
1030 idAnimManager::ListAnims
1031 ================
1032 */
1033 void idAnimManager::ListAnims( void ) const {
1034         int                     i;
1035         idMD5Anim       **animptr;
1036         idMD5Anim       *anim;
1037         size_t          size;
1038         size_t          s;
1039         size_t          namesize;
1040         int                     num;
1041
1042         num = 0;
1043         size = 0;
1044         for( i = 0; i < animations.Num(); i++ ) {
1045                 animptr = animations.GetIndex( i );
1046                 if ( animptr && *animptr ) {
1047                         anim = *animptr;
1048                         s = anim->Size();
1049                         gameLocal.Printf( "%8d bytes : %2d refs : %s\n", s, anim->NumRefs(), anim->Name() );
1050                         size += s;
1051                         num++;
1052                 }
1053         }
1054
1055         namesize = jointnames.Size() + jointnamesHash.Size();
1056         for( i = 0; i < jointnames.Num(); i++ ) {
1057                 namesize += jointnames[ i ].Size();
1058         }
1059
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() );
1062 }
1063
1064 /*
1065 ================
1066 idAnimManager::FlushUnusedAnims
1067 ================
1068 */
1069 void idAnimManager::FlushUnusedAnims( void ) {
1070         int                                             i;
1071         idMD5Anim                               **animptr;
1072         idList<idMD5Anim *>             removeAnims;
1073         
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 );
1079                         }
1080                 }
1081         }
1082
1083         for( i = 0; i < removeAnims.Num(); i++ ) {
1084                 animations.Remove( removeAnims[ i ]->Name() );
1085                 delete removeAnims[ i ];
1086         }
1087 }