doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Anim_Blend.cpp
Go to the documentation of this file.
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 static const char *channelNames[ ANIM_NumAnimChannels ] = {
35  "all", "torso", "legs", "head", "eyelids"
36 };
37 
38 /***********************************************************************
39 
40  idAnim
41 
42 ***********************************************************************/
43 
44 /*
45 =====================
46 idAnim::idAnim
47 =====================
48 */
50  modelDef = NULL;
51  numAnims = 0;
52  memset( anims, 0, sizeof( anims ) );
53  memset( &flags, 0, sizeof( flags ) );
54 }
55 
56 /*
57 =====================
58 idAnim::idAnim
59 =====================
60 */
61 idAnim::idAnim( const idDeclModelDef *modelDef, const idAnim *anim ) {
62  int i;
63 
64  this->modelDef = modelDef;
65  numAnims = anim->numAnims;
66  name = anim->name;
67  realname = anim->realname;
68  flags = anim->flags;
69 
70  memset( anims, 0, sizeof( anims ) );
71  for( i = 0; i < numAnims; i++ ) {
72  anims[ i ] = anim->anims[ i ];
73  anims[ i ]->IncreaseRefs();
74  }
75 
76  frameLookup.SetNum( anim->frameLookup.Num() );
77  memcpy( frameLookup.Ptr(), anim->frameLookup.Ptr(), frameLookup.MemoryUsed() );
78 
80  for( i = 0; i < frameCommands.Num(); i++ ) {
81  frameCommands[ i ] = anim->frameCommands[ i ];
82  if ( anim->frameCommands[ i ].string ) {
83  frameCommands[ i ].string = new idStr( *anim->frameCommands[ i ].string );
84  }
85  }
86 }
87 
88 /*
89 =====================
90 idAnim::~idAnim
91 =====================
92 */
94  int i;
95 
96  for( i = 0; i < numAnims; i++ ) {
97  anims[ i ]->DecreaseRefs();
98  }
99 
100  for( i = 0; i < frameCommands.Num(); i++ ) {
101  delete frameCommands[ i ].string;
102  }
103 }
104 
105 /*
106 =====================
107 idAnim::SetAnim
108 =====================
109 */
110 void idAnim::SetAnim( const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ] ) {
111  int i;
112 
113  this->modelDef = modelDef;
114 
115  for( i = 0; i < numAnims; i++ ) {
116  anims[ i ]->DecreaseRefs();
117  anims[ i ] = NULL;
118  }
119 
120  assert( ( num > 0 ) && ( num <= ANIM_MaxSyncedAnims ) );
121  numAnims = num;
122  realname = sourcename;
123  name = animname;
124 
125  for( i = 0; i < num; i++ ) {
126  anims[ i ] = md5anims[ i ];
127  anims[ i ]->IncreaseRefs();
128  }
129 
130  memset( &flags, 0, sizeof( flags ) );
131 
132  for( i = 0; i < frameCommands.Num(); i++ ) {
133  delete frameCommands[ i ].string;
134  }
135 
136  frameLookup.Clear();
138 }
139 
140 /*
141 =====================
142 idAnim::Name
143 =====================
144 */
145 const char *idAnim::Name( void ) const {
146  return name;
147 }
148 
149 /*
150 =====================
151 idAnim::FullName
152 =====================
153 */
154 const char *idAnim::FullName( void ) const {
155  return realname;
156 }
157 
158 /*
159 =====================
160 idAnim::MD5Anim
161 
162 index 0 will never be NULL. Any anim >= NumAnims will return NULL.
163 =====================
164 */
165 const idMD5Anim *idAnim::MD5Anim( int num ) const {
166  if ( anims == NULL || anims[0] == NULL ) {
167  return NULL;
168  }
169  return anims[ num ];
170 }
171 
172 /*
173 =====================
174 idAnim::ModelDef
175 =====================
176 */
177 const idDeclModelDef *idAnim::ModelDef( void ) const {
178  return modelDef;
179 }
180 
181 /*
182 =====================
183 idAnim::Length
184 =====================
185 */
186 int idAnim::Length( void ) const {
187  if ( !anims[ 0 ] ) {
188  return 0;
189  }
190 
191  return anims[ 0 ]->Length();
192 }
193 
194 /*
195 =====================
196 idAnim::NumFrames
197 =====================
198 */
199 int idAnim::NumFrames( void ) const {
200  if ( !anims[ 0 ] ) {
201  return 0;
202  }
203 
204  return anims[ 0 ]->NumFrames();
205 }
206 
207 /*
208 =====================
209 idAnim::NumAnims
210 =====================
211 */
212 int idAnim::NumAnims( void ) const {
213  return numAnims;
214 }
215 
216 /*
217 =====================
218 idAnim::TotalMovementDelta
219 =====================
220 */
221 const idVec3 &idAnim::TotalMovementDelta( void ) const {
222  if ( !anims[ 0 ] ) {
223  return vec3_zero;
224  }
225 
226  return anims[ 0 ]->TotalMovementDelta();
227 }
228 
229 /*
230 =====================
231 idAnim::GetOrigin
232 =====================
233 */
234 bool idAnim::GetOrigin( idVec3 &offset, int animNum, int currentTime, int cyclecount ) const {
235  if ( !anims[ animNum ] ) {
236  offset.Zero();
237  return false;
238  }
239 
240  anims[ animNum ]->GetOrigin( offset, currentTime, cyclecount );
241  return true;
242 }
243 
244 /*
245 =====================
246 idAnim::GetOriginRotation
247 =====================
248 */
249 bool idAnim::GetOriginRotation( idQuat &rotation, int animNum, int currentTime, int cyclecount ) const {
250  if ( !anims[ animNum ] ) {
251  rotation.Set( 0.0f, 0.0f, 0.0f, 1.0f );
252  return false;
253  }
254 
255  anims[ animNum ]->GetOriginRotation( rotation, currentTime, cyclecount );
256  return true;
257 }
258 
259 /*
260 =====================
261 idAnim::GetBounds
262 =====================
263 */
264 ID_INLINE bool idAnim::GetBounds( idBounds &bounds, int animNum, int currentTime, int cyclecount ) const {
265  if ( !anims[ animNum ] ) {
266  return false;
267  }
268 
269  anims[ animNum ]->GetBounds( bounds, currentTime, cyclecount );
270  return true;
271 }
272 
273 
274 /*
275 =====================
276 idAnim::AddFrameCommand
277 
278 Returns NULL if no error.
279 =====================
280 */
281 const char *idAnim::AddFrameCommand( const idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def ) {
282  int i;
283  int index;
284  idStr text;
285  idStr funcname;
286  frameCommand_t fc;
287  idToken token;
288  const jointInfo_t *jointInfo;
289 
290  // make sure we're within bounds
291  if ( ( framenum < 1 ) || ( framenum > anims[ 0 ]->NumFrames() ) ) {
292  return va( "Frame %d out of range", framenum );
293  }
294 
295  // frame numbers are 1 based in .def files, but 0 based internally
296  framenum--;
297 
298  memset( &fc, 0, sizeof( fc ) );
299 
300  if( !src.ReadTokenOnLine( &token ) ) {
301  return "Unexpected end of line";
302  }
303  if ( token == "call" ) {
304  if( !src.ReadTokenOnLine( &token ) ) {
305  return "Unexpected end of line";
306  }
307  fc.type = FC_SCRIPTFUNCTION;
308  fc.function = gameLocal.program.FindFunction( token );
309  if ( !fc.function ) {
310  return va( "Function '%s' not found", token.c_str() );
311  }
312  } else if ( token == "object_call" ) {
313  if( !src.ReadTokenOnLine( &token ) ) {
314  return "Unexpected end of line";
315  }
317  fc.string = new idStr( token );
318  } else if ( token == "event" ) {
319  if( !src.ReadTokenOnLine( &token ) ) {
320  return "Unexpected end of line";
321  }
322  fc.type = FC_EVENTFUNCTION;
323  const idEventDef *ev = idEventDef::FindEvent( token );
324  if ( !ev ) {
325  return va( "Event '%s' not found", token.c_str() );
326  }
327  if ( ev->GetNumArgs() != 0 ) {
328  return va( "Event '%s' has arguments", token.c_str() );
329  }
330  fc.string = new idStr( token );
331  } else if ( token == "sound" ) {
332  if( !src.ReadTokenOnLine( &token ) ) {
333  return "Unexpected end of line";
334  }
335  fc.type = FC_SOUND;
336  if ( !token.Cmpn( "snd_", 4 ) ) {
337  fc.string = new idStr( token );
338  } else {
339  fc.soundShader = declManager->FindSound( token );
340  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
341  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
342  }
343  }
344  } else if ( token == "sound_voice" ) {
345  if( !src.ReadTokenOnLine( &token ) ) {
346  return "Unexpected end of line";
347  }
348  fc.type = FC_SOUND_VOICE;
349  if ( !token.Cmpn( "snd_", 4 ) ) {
350  fc.string = new idStr( token );
351  } else {
352  fc.soundShader = declManager->FindSound( token );
353  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
354  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
355  }
356  }
357  } else if ( token == "sound_voice2" ) {
358  if( !src.ReadTokenOnLine( &token ) ) {
359  return "Unexpected end of line";
360  }
361  fc.type = FC_SOUND_VOICE2;
362  if ( !token.Cmpn( "snd_", 4 ) ) {
363  fc.string = new idStr( token );
364  } else {
365  fc.soundShader = declManager->FindSound( token );
366  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
367  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
368  }
369  }
370  } else if ( token == "sound_body" ) {
371  if( !src.ReadTokenOnLine( &token ) ) {
372  return "Unexpected end of line";
373  }
374  fc.type = FC_SOUND_BODY;
375  if ( !token.Cmpn( "snd_", 4 ) ) {
376  fc.string = new idStr( token );
377  } else {
378  fc.soundShader = declManager->FindSound( token );
379  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
380  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
381  }
382  }
383  } else if ( token == "sound_body2" ) {
384  if( !src.ReadTokenOnLine( &token ) ) {
385  return "Unexpected end of line";
386  }
387  fc.type = FC_SOUND_BODY2;
388  if ( !token.Cmpn( "snd_", 4 ) ) {
389  fc.string = new idStr( token );
390  } else {
391  fc.soundShader = declManager->FindSound( token );
392  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
393  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
394  }
395  }
396  } else if ( token == "sound_body3" ) {
397  if( !src.ReadTokenOnLine( &token ) ) {
398  return "Unexpected end of line";
399  }
400  fc.type = FC_SOUND_BODY3;
401  if ( !token.Cmpn( "snd_", 4 ) ) {
402  fc.string = new idStr( token );
403  } else {
404  fc.soundShader = declManager->FindSound( token );
405  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
406  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
407  }
408  }
409  } else if ( token == "sound_weapon" ) {
410  if( !src.ReadTokenOnLine( &token ) ) {
411  return "Unexpected end of line";
412  }
413  fc.type = FC_SOUND_WEAPON;
414  if ( !token.Cmpn( "snd_", 4 ) ) {
415  fc.string = new idStr( token );
416  } else {
417  fc.soundShader = declManager->FindSound( token );
418  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
419  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
420  }
421  }
422  } else if ( token == "sound_global" ) {
423  if( !src.ReadTokenOnLine( &token ) ) {
424  return "Unexpected end of line";
425  }
426  fc.type = FC_SOUND_GLOBAL;
427  if ( !token.Cmpn( "snd_", 4 ) ) {
428  fc.string = new idStr( token );
429  } else {
430  fc.soundShader = declManager->FindSound( token );
431  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
432  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
433  }
434  }
435  } else if ( token == "sound_item" ) {
436  if( !src.ReadTokenOnLine( &token ) ) {
437  return "Unexpected end of line";
438  }
439  fc.type = FC_SOUND_ITEM;
440  if ( !token.Cmpn( "snd_", 4 ) ) {
441  fc.string = new idStr( token );
442  } else {
443  fc.soundShader = declManager->FindSound( token );
444  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
445  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
446  }
447  }
448  } else if ( token == "sound_chatter" ) {
449  if( !src.ReadTokenOnLine( &token ) ) {
450  return "Unexpected end of line";
451  }
452  fc.type = FC_SOUND_CHATTER;
453  if ( !token.Cmpn( "snd_", 4 ) ) {
454  fc.string = new idStr( token );
455  } else {
456  fc.soundShader = declManager->FindSound( token );
457  if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
458  gameLocal.Warning( "Sound '%s' not found", token.c_str() );
459  }
460  }
461  } else if ( token == "skin" ) {
462  if( !src.ReadTokenOnLine( &token ) ) {
463  return "Unexpected end of line";
464  }
465  fc.type = FC_SKIN;
466  if ( token == "none" ) {
467  fc.skin = NULL;
468  } else {
469  fc.skin = declManager->FindSkin( token );
470  if ( !fc.skin ) {
471  return va( "Skin '%s' not found", token.c_str() );
472  }
473  }
474  } else if ( token == "fx" ) {
475  if( !src.ReadTokenOnLine( &token ) ) {
476  return "Unexpected end of line";
477  }
478  fc.type = FC_FX;
479  if ( !declManager->FindType( DECL_FX, token.c_str() ) ) {
480  return va( "fx '%s' not found", token.c_str() );
481  }
482  fc.string = new idStr( token );
483  } else if ( token == "trigger" ) {
484  if( !src.ReadTokenOnLine( &token ) ) {
485  return "Unexpected end of line";
486  }
487  fc.type = FC_TRIGGER;
488  fc.string = new idStr( token );
489  } else if ( token == "triggerSmokeParticle" ) {
490  if( !src.ReadTokenOnLine( &token ) ) {
491  return "Unexpected end of line";
492  }
494  fc.string = new idStr( token );
495  } else if ( token == "melee" ) {
496  if( !src.ReadTokenOnLine( &token ) ) {
497  return "Unexpected end of line";
498  }
499  fc.type = FC_MELEE;
500  if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
501  return va( "Unknown entityDef '%s'", token.c_str() );
502  }
503  fc.string = new idStr( token );
504  } else if ( token == "direct_damage" ) {
505  if( !src.ReadTokenOnLine( &token ) ) {
506  return "Unexpected end of line";
507  }
508  fc.type = FC_DIRECTDAMAGE;
509  if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
510  return va( "Unknown entityDef '%s'", token.c_str() );
511  }
512  fc.string = new idStr( token );
513  } else if ( token == "attack_begin" ) {
514  if( !src.ReadTokenOnLine( &token ) ) {
515  return "Unexpected end of line";
516  }
517  fc.type = FC_BEGINATTACK;
518  if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
519  return va( "Unknown entityDef '%s'", token.c_str() );
520  }
521  fc.string = new idStr( token );
522  } else if ( token == "attack_end" ) {
523  fc.type = FC_ENDATTACK;
524  } else if ( token == "muzzle_flash" ) {
525  if( !src.ReadTokenOnLine( &token ) ) {
526  return "Unexpected end of line";
527  }
528  if ( ( token != "" ) && !modelDef->FindJoint( token ) ) {
529  return va( "Joint '%s' not found", token.c_str() );
530  }
531  fc.type = FC_MUZZLEFLASH;
532  fc.string = new idStr( token );
533  } else if ( token == "muzzle_flash" ) {
534  fc.type = FC_MUZZLEFLASH;
535  fc.string = new idStr( "" );
536  } else if ( token == "create_missile" ) {
537  if( !src.ReadTokenOnLine( &token ) ) {
538  return "Unexpected end of line";
539  }
540  if ( !modelDef->FindJoint( token ) ) {
541  return va( "Joint '%s' not found", token.c_str() );
542  }
543  fc.type = FC_CREATEMISSILE;
544  fc.string = new idStr( token );
545  } else if ( token == "launch_missile" ) {
546  if( !src.ReadTokenOnLine( &token ) ) {
547  return "Unexpected end of line";
548  }
549  if ( !modelDef->FindJoint( token ) ) {
550  return va( "Joint '%s' not found", token.c_str() );
551  }
552  fc.type = FC_LAUNCHMISSILE;
553  fc.string = new idStr( token );
554  } else if ( token == "fire_missile_at_target" ) {
555  if( !src.ReadTokenOnLine( &token ) ) {
556  return "Unexpected end of line";
557  }
558  jointInfo = modelDef->FindJoint( token );
559  if ( !jointInfo ) {
560  return va( "Joint '%s' not found", token.c_str() );
561  }
562  if( !src.ReadTokenOnLine( &token ) ) {
563  return "Unexpected end of line";
564  }
566  fc.string = new idStr( token );
567  fc.index = jointInfo->num;
568 #ifdef _D3XP
569  } else if ( token == "launch_projectile" ) {
570  if( !src.ReadTokenOnLine( &token ) ) {
571  return "Unexpected end of line";
572  }
573  if ( !declManager->FindDeclWithoutParsing( DECL_ENTITYDEF, token, false ) ) {
574  return "Unknown projectile def";
575  }
576  fc.type = FC_LAUNCH_PROJECTILE;
577  fc.string = new idStr( token );
578  } else if ( token == "trigger_fx" ) {
579 
580  if( !src.ReadTokenOnLine( &token ) ) {
581  return "Unexpected end of line";
582  }
583  jointInfo = modelDef->FindJoint( token );
584  if ( !jointInfo ) {
585  return va( "Joint '%s' not found", token.c_str() );
586  }
587  if( !src.ReadTokenOnLine( &token ) ) {
588  return "Unexpected end of line";
589  }
590  if ( !declManager->FindType( DECL_FX, token, false ) ) {
591  return "Unknown FX def";
592  }
593 
594  fc.type = FC_TRIGGER_FX;
595  fc.string = new idStr( token );
596  fc.index = jointInfo->num;
597 
598  } else if ( token == "start_emitter" ) {
599 
600  idStr str;
601  if( !src.ReadTokenOnLine( &token ) ) {
602  return "Unexpected end of line";
603  }
604  str = token + " ";
605 
606  if( !src.ReadTokenOnLine( &token ) ) {
607  return "Unexpected end of line";
608  }
609  jointInfo = modelDef->FindJoint( token );
610  if ( !jointInfo ) {
611  return va( "Joint '%s' not found", token.c_str() );
612  }
613  if( !src.ReadTokenOnLine( &token ) ) {
614  return "Unexpected end of line";
615  }
616  str += token;
617  fc.type = FC_START_EMITTER;
618  fc.string = new idStr( str );
619  fc.index = jointInfo->num;
620 
621  } else if ( token == "stop_emitter" ) {
622 
623  if( !src.ReadTokenOnLine( &token ) ) {
624  return "Unexpected end of line";
625  }
626  fc.type = FC_STOP_EMITTER;
627  fc.string = new idStr( token );
628 #endif
629  } else if ( token == "footstep" ) {
630  fc.type = FC_FOOTSTEP;
631  } else if ( token == "leftfoot" ) {
632  fc.type = FC_LEFTFOOT;
633  } else if ( token == "rightfoot" ) {
634  fc.type = FC_RIGHTFOOT;
635  } else if ( token == "enableEyeFocus" ) {
637  } else if ( token == "disableEyeFocus" ) {
639  } else if ( token == "disableGravity" ) {
641  } else if ( token == "enableGravity" ) {
642  fc.type = FC_ENABLE_GRAVITY;
643  } else if ( token == "jump" ) {
644  fc.type = FC_JUMP;
645  } else if ( token == "enableClip" ) {
646  fc.type = FC_ENABLE_CLIP;
647  } else if ( token == "disableClip" ) {
648  fc.type = FC_DISABLE_CLIP;
649  } else if ( token == "enableWalkIK" ) {
650  fc.type = FC_ENABLE_WALK_IK;
651  } else if ( token == "disableWalkIK" ) {
653  } else if ( token == "enableLegIK" ) {
654  if( !src.ReadTokenOnLine( &token ) ) {
655  return "Unexpected end of line";
656  }
657  fc.type = FC_ENABLE_LEG_IK;
658  fc.index = atoi( token );
659  } else if ( token == "disableLegIK" ) {
660  if( !src.ReadTokenOnLine( &token ) ) {
661  return "Unexpected end of line";
662  }
663  fc.type = FC_DISABLE_LEG_IK;
664  fc.index = atoi( token );
665  } else if ( token == "recordDemo" ) {
666  fc.type = FC_RECORDDEMO;
667  if( src.ReadTokenOnLine( &token ) ) {
668  fc.string = new idStr( token );
669  }
670  } else if ( token == "aviGame" ) {
671  fc.type = FC_AVIGAME;
672  if( src.ReadTokenOnLine( &token ) ) {
673  fc.string = new idStr( token );
674  }
675  } else {
676  return va( "Unknown command '%s'", token.c_str() );
677  }
678 
679  // check if we've initialized the frame loopup table
680  if ( !frameLookup.Num() ) {
681  // we haven't, so allocate the table and initialize it
683  frameLookup.SetNum( anims[ 0 ]->NumFrames() );
684  for( i = 0; i < frameLookup.Num(); i++ ) {
685  frameLookup[ i ].num = 0;
686  frameLookup[ i ].firstCommand = 0;
687  }
688  }
689 
690  // allocate space for a new command
692 
693  // calculate the index of the new command
694  index = frameLookup[ framenum ].firstCommand + frameLookup[ framenum ].num;
695 
696  // move all commands from our index onward up one to give us space for our new command
697  for( i = frameCommands.Num() - 1; i > index; i-- ) {
698  frameCommands[ i ] = frameCommands[ i - 1 ];
699  }
700 
701  // fix the indices of any later frames to account for the inserted command
702  for( i = framenum + 1; i < frameLookup.Num(); i++ ) {
703  frameLookup[ i ].firstCommand++;
704  }
705 
706  // store the new command
707  frameCommands[ index ] = fc;
708 
709  // increase the number of commands on this frame
710  frameLookup[ framenum ].num++;
711 
712  // return with no error
713  return NULL;
714 }
715 
716 /*
717 =====================
718 idAnim::CallFrameCommands
719 =====================
720 */
721 void idAnim::CallFrameCommands( idEntity *ent, int from, int to ) const {
722  int index;
723  int end;
724  int frame;
725  int numframes;
726 
727  numframes = anims[ 0 ]->NumFrames();
728 
729  frame = from;
730  while( frame != to ) {
731  frame++;
732  if ( frame >= numframes ) {
733  frame = 0;
734  }
735 
736  index = frameLookup[ frame ].firstCommand;
737  end = index + frameLookup[ frame ].num;
738  while( index < end ) {
739  const frameCommand_t &command = frameCommands[ index++ ];
740  switch( command.type ) {
741  case FC_SCRIPTFUNCTION: {
742  gameLocal.CallFrameCommand( ent, command.function );
743  break;
744  }
746  gameLocal.CallObjectFrameCommand( ent, command.string->c_str() );
747  break;
748  }
749  case FC_EVENTFUNCTION: {
750  const idEventDef *ev = idEventDef::FindEvent( command.string->c_str() );
751  ent->ProcessEvent( ev );
752  break;
753  }
754  case FC_SOUND: {
755  if ( !command.soundShader ) {
756  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, 0, false, NULL ) ) {
757  gameLocal.Warning( "Framecommand 'sound' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
758  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
759  }
760  } else {
761  ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, 0, false, NULL );
762  }
763  break;
764  }
765  case FC_SOUND_VOICE: {
766  if ( !command.soundShader ) {
767  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) {
768  gameLocal.Warning( "Framecommand 'sound_voice' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
769  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
770  }
771  } else {
772  ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL );
773  }
774  break;
775  }
776  case FC_SOUND_VOICE2: {
777  if ( !command.soundShader ) {
778  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE2, 0, false, NULL ) ) {
779  gameLocal.Warning( "Framecommand 'sound_voice2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
780  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
781  }
782  } else {
783  ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE2, 0, false, NULL );
784  }
785  break;
786  }
787  case FC_SOUND_BODY: {
788  if ( !command.soundShader ) {
789  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY, 0, false, NULL ) ) {
790  gameLocal.Warning( "Framecommand 'sound_body' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
791  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
792  }
793  } else {
794  ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY, 0, false, NULL );
795  }
796  break;
797  }
798  case FC_SOUND_BODY2: {
799  if ( !command.soundShader ) {
800  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY2, 0, false, NULL ) ) {
801  gameLocal.Warning( "Framecommand 'sound_body2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
802  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
803  }
804  } else {
805  ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY2, 0, false, NULL );
806  }
807  break;
808  }
809  case FC_SOUND_BODY3: {
810  if ( !command.soundShader ) {
811  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY3, 0, false, NULL ) ) {
812  gameLocal.Warning( "Framecommand 'sound_body3' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
813  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
814  }
815  } else {
816  ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY3, 0, false, NULL );
817  }
818  break;
819  }
820  case FC_SOUND_WEAPON: {
821  if ( !command.soundShader ) {
822  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_WEAPON, 0, false, NULL ) ) {
823  gameLocal.Warning( "Framecommand 'sound_weapon' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
824  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
825  }
826  } else {
827  ent->StartSoundShader( command.soundShader, SND_CHANNEL_WEAPON, 0, false, NULL );
828  }
829  break;
830  }
831  case FC_SOUND_GLOBAL: {
832  if ( !command.soundShader ) {
833  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ) ) {
834  gameLocal.Warning( "Framecommand 'sound_global' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
835  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
836  }
837  } else {
838  ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
839  }
840  break;
841  }
842  case FC_SOUND_ITEM: {
843  if ( !command.soundShader ) {
844  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ITEM, 0, false, NULL ) ) {
845  gameLocal.Warning( "Framecommand 'sound_item' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
846  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
847  }
848  } else {
849  ent->StartSoundShader( command.soundShader, SND_CHANNEL_ITEM, 0, false, NULL );
850  }
851  break;
852  }
853  case FC_SOUND_CHATTER: {
854  if ( ent->CanPlayChatterSounds() ) {
855  if ( !command.soundShader ) {
856  if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) {
857  gameLocal.Warning( "Framecommand 'sound_chatter' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
858  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
859  }
860  } else {
861  ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL );
862  }
863  }
864  break;
865  }
866  case FC_FX: {
867  idEntityFx::StartFx( command.string->c_str(), NULL, NULL, ent, true );
868  break;
869  }
870  case FC_SKIN: {
871  ent->SetSkin( command.skin );
872  break;
873  }
874  case FC_TRIGGER: {
875  idEntity *target;
876 
877  target = gameLocal.FindEntity( command.string->c_str() );
878  if ( target ) {
879 #ifdef _D3XP
880  SetTimeState ts(target->timeGroup);
881 #endif
882  target->Signal( SIG_TRIGGER );
883  target->ProcessEvent( &EV_Activate, ent );
884  target->TriggerGuis();
885  } else {
886  gameLocal.Warning( "Framecommand 'trigger' on entity '%s', anim '%s', frame %d: Could not find entity '%s'",
887  ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
888  }
889  break;
890  }
892  ent->ProcessEvent( &AI_TriggerParticles, command.string->c_str() );
893  break;
894  }
895  case FC_MELEE: {
896  ent->ProcessEvent( &AI_AttackMelee, command.string->c_str() );
897  break;
898  }
899  case FC_DIRECTDAMAGE: {
900  ent->ProcessEvent( &AI_DirectDamage, command.string->c_str() );
901  break;
902  }
903  case FC_BEGINATTACK: {
904  ent->ProcessEvent( &AI_BeginAttack, command.string->c_str() );
905  break;
906  }
907  case FC_ENDATTACK: {
908  ent->ProcessEvent( &AI_EndAttack );
909  break;
910  }
911  case FC_MUZZLEFLASH: {
912  ent->ProcessEvent( &AI_MuzzleFlash, command.string->c_str() );
913  break;
914  }
915  case FC_CREATEMISSILE: {
916  ent->ProcessEvent( &AI_CreateMissile, command.string->c_str() );
917  break;
918  }
919  case FC_LAUNCHMISSILE: {
920  ent->ProcessEvent( &AI_AttackMissile, command.string->c_str() );
921  break;
922  }
923  case FC_FIREMISSILEATTARGET: {
924  ent->ProcessEvent( &AI_FireMissileAtTarget, modelDef->GetJointName( command.index ), command.string->c_str() );
925  break;
926  }
927 #ifdef _D3XP
928  case FC_LAUNCH_PROJECTILE: {
929  ent->ProcessEvent( &AI_LaunchProjectile, command.string->c_str() );
930  break;
931  }
932  case FC_TRIGGER_FX: {
933  ent->ProcessEvent( &AI_TriggerFX, modelDef->GetJointName( command.index ), command.string->c_str() );
934  break;
935  }
936  case FC_START_EMITTER: {
937  int index = command.string->Find(" ");
938  if(index >= 0) {
939  idStr name = command.string->Left(index);
940  idStr particle = command.string->Right(command.string->Length() - index - 1);
941  ent->ProcessEvent( &AI_StartEmitter, name.c_str(), modelDef->GetJointName( command.index ), particle.c_str() );
942  }
943  }
944 
945  case FC_STOP_EMITTER: {
946  ent->ProcessEvent( &AI_StopEmitter, command.string->c_str() );
947  }
948 #endif
949  case FC_FOOTSTEP : {
950  ent->ProcessEvent( &EV_Footstep );
951  break;
952  }
953  case FC_LEFTFOOT: {
954  ent->ProcessEvent( &EV_FootstepLeft );
955  break;
956  }
957  case FC_RIGHTFOOT: {
959  break;
960  }
961  case FC_ENABLE_EYE_FOCUS: {
963  break;
964  }
965  case FC_DISABLE_EYE_FOCUS: {
967  break;
968  }
969  case FC_DISABLE_GRAVITY: {
971  break;
972  }
973  case FC_ENABLE_GRAVITY: {
975  break;
976  }
977  case FC_JUMP: {
978  ent->ProcessEvent( &AI_JumpFrame );
979  break;
980  }
981  case FC_ENABLE_CLIP: {
982  ent->ProcessEvent( &AI_EnableClip );
983  break;
984  }
985  case FC_DISABLE_CLIP: {
986  ent->ProcessEvent( &AI_DisableClip );
987  break;
988  }
989  case FC_ENABLE_WALK_IK: {
990  ent->ProcessEvent( &EV_EnableWalkIK );
991  break;
992  }
993  case FC_DISABLE_WALK_IK: {
995  break;
996  }
997  case FC_ENABLE_LEG_IK: {
998  ent->ProcessEvent( &EV_EnableLegIK, command.index );
999  break;
1000  }
1001  case FC_DISABLE_LEG_IK: {
1002  ent->ProcessEvent( &EV_DisableLegIK, command.index );
1003  break;
1004  }
1005  case FC_RECORDDEMO: {
1006  if ( command.string ) {
1007  cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "recordDemo %s", command.string->c_str() ) );
1008  } else {
1009  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "stoprecording" );
1010  }
1011  break;
1012  }
1013  case FC_AVIGAME: {
1014  if ( command.string ) {
1015  cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "aviGame %s", command.string->c_str() ) );
1016  } else {
1017  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "aviGame" );
1018  }
1019  break;
1020  }
1021  }
1022  }
1023  }
1024 }
1025 
1026 /*
1027 =====================
1028 idAnim::FindFrameForFrameCommand
1029 =====================
1030 */
1031 int idAnim::FindFrameForFrameCommand( frameCommandType_t framecommand, const frameCommand_t **command ) const {
1032  int frame;
1033  int index;
1034  int numframes;
1035  int end;
1036 
1037  if ( !frameCommands.Num() ) {
1038  return -1;
1039  }
1040 
1041  numframes = anims[ 0 ]->NumFrames();
1042  for( frame = 0; frame < numframes; frame++ ) {
1043  end = frameLookup[ frame ].firstCommand + frameLookup[ frame ].num;
1044  for( index = frameLookup[ frame ].firstCommand; index < end; index++ ) {
1045  if ( frameCommands[ index ].type == framecommand ) {
1046  if ( command ) {
1047  *command = &frameCommands[ index ];
1048  }
1049  return frame;
1050  }
1051  }
1052  }
1053 
1054  if ( command ) {
1055  *command = NULL;
1056  }
1057 
1058  return -1;
1059 }
1060 
1061 /*
1062 =====================
1063 idAnim::HasFrameCommands
1064 =====================
1065 */
1066 bool idAnim::HasFrameCommands( void ) const {
1067  if ( !frameCommands.Num() ) {
1068  return false;
1069  }
1070  return true;
1071 }
1072 
1073 /*
1074 =====================
1075 idAnim::SetAnimFlags
1076 =====================
1077 */
1078 void idAnim::SetAnimFlags( const animFlags_t &animflags ) {
1079  flags = animflags;
1080 }
1081 
1082 /*
1083 =====================
1084 idAnim::GetAnimFlags
1085 =====================
1086 */
1087 const animFlags_t &idAnim::GetAnimFlags( void ) const {
1088  return flags;
1089 }
1090 
1091 /***********************************************************************
1092 
1093  idAnimBlend
1094 
1095 ***********************************************************************/
1096 
1097 /*
1098 =====================
1099 idAnimBlend::idAnimBlend
1100 =====================
1101 */
1103  Reset( NULL );
1104 }
1105 
1106 /*
1107 =====================
1108 idAnimBlend::Save
1109 
1110 archives object for save game file
1111 =====================
1112 */
1113 void idAnimBlend::Save( idSaveGame *savefile ) const {
1114  int i;
1115 
1116  savefile->WriteInt( starttime );
1117  savefile->WriteInt( endtime );
1118  savefile->WriteInt( timeOffset );
1119  savefile->WriteFloat( rate );
1120 
1121  savefile->WriteInt( blendStartTime );
1122  savefile->WriteInt( blendDuration );
1123  savefile->WriteFloat( blendStartValue );
1124  savefile->WriteFloat( blendEndValue );
1125 
1126  for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) {
1127  savefile->WriteFloat( animWeights[ i ] );
1128  }
1129  savefile->WriteShort( cycle );
1130  savefile->WriteShort( frame );
1131  savefile->WriteShort( animNum );
1132  savefile->WriteBool( allowMove );
1133  savefile->WriteBool( allowFrameCommands );
1134 }
1135 
1136 /*
1137 =====================
1138 idAnimBlend::Restore
1139 
1140 unarchives object from save game file
1141 =====================
1142 */
1143 void idAnimBlend::Restore( idRestoreGame *savefile, const idDeclModelDef *modelDef ) {
1144  int i;
1145 
1146  this->modelDef = modelDef;
1147 
1148  savefile->ReadInt( starttime );
1149  savefile->ReadInt( endtime );
1150  savefile->ReadInt( timeOffset );
1151  savefile->ReadFloat( rate );
1152 
1153  savefile->ReadInt( blendStartTime );
1154  savefile->ReadInt( blendDuration );
1155  savefile->ReadFloat( blendStartValue );
1156  savefile->ReadFloat( blendEndValue );
1157 
1158  for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) {
1159  savefile->ReadFloat( animWeights[ i ] );
1160  }
1161  savefile->ReadShort( cycle );
1162  savefile->ReadShort( frame );
1163  savefile->ReadShort( animNum );
1164  if ( !modelDef ) {
1165  animNum = 0;
1166  } else if ( ( animNum < 0 ) || ( animNum > modelDef->NumAnims() ) ) {
1167  gameLocal.Warning( "Anim number %d out of range for model '%s' during save game", animNum, modelDef->GetModelName() );
1168  animNum = 0;
1169  }
1170  savefile->ReadBool( allowMove );
1171  savefile->ReadBool( allowFrameCommands );
1172 }
1173 
1174 /*
1175 =====================
1176 idAnimBlend::Reset
1177 =====================
1178 */
1179 void idAnimBlend::Reset( const idDeclModelDef *_modelDef ) {
1180  modelDef = _modelDef;
1181  cycle = 1;
1182  starttime = 0;
1183  endtime = 0;
1184  timeOffset = 0;
1185  rate = 1.0f;
1186  frame = 0;
1187  allowMove = true;
1188  allowFrameCommands = true;
1189  animNum = 0;
1190 
1191  memset( animWeights, 0, sizeof( animWeights ) );
1192 
1193  blendStartValue = 0.0f;
1194  blendEndValue = 0.0f;
1195  blendStartTime = 0;
1196  blendDuration = 0;
1197 }
1198 
1199 /*
1200 =====================
1201 idAnimBlend::FullName
1202 =====================
1203 */
1204 const char *idAnimBlend::AnimFullName( void ) const {
1205  const idAnim *anim = Anim();
1206  if ( !anim ) {
1207  return "";
1208  }
1209 
1210  return anim->FullName();
1211 }
1212 
1213 /*
1214 =====================
1215 idAnimBlend::AnimName
1216 =====================
1217 */
1218 const char *idAnimBlend::AnimName( void ) const {
1219  const idAnim *anim = Anim();
1220  if ( !anim ) {
1221  return "";
1222  }
1223 
1224  return anim->Name();
1225 }
1226 
1227 /*
1228 =====================
1229 idAnimBlend::NumFrames
1230 =====================
1231 */
1232 int idAnimBlend::NumFrames( void ) const {
1233  const idAnim *anim = Anim();
1234  if ( !anim ) {
1235  return 0;
1236  }
1237 
1238  return anim->NumFrames();
1239 }
1240 
1241 /*
1242 =====================
1243 idAnimBlend::Length
1244 =====================
1245 */
1246 int idAnimBlend::Length( void ) const {
1247  const idAnim *anim = Anim();
1248  if ( !anim ) {
1249  return 0;
1250  }
1251 
1252  return anim->Length();
1253 }
1254 
1255 /*
1256 =====================
1257 idAnimBlend::GetWeight
1258 =====================
1259 */
1260 float idAnimBlend::GetWeight( int currentTime ) const {
1261  int timeDelta;
1262  float frac;
1263  float w;
1264 
1265  timeDelta = currentTime - blendStartTime;
1266  if ( timeDelta <= 0 ) {
1267  w = blendStartValue;
1268  } else if ( timeDelta >= blendDuration ) {
1269  w = blendEndValue;
1270  } else {
1271  frac = ( float )timeDelta / ( float )blendDuration;
1272  w = blendStartValue + ( blendEndValue - blendStartValue ) * frac;
1273  }
1274 
1275  return w;
1276 }
1277 
1278 /*
1279 =====================
1280 idAnimBlend::GetFinalWeight
1281 =====================
1282 */
1283 float idAnimBlend::GetFinalWeight( void ) const {
1284  return blendEndValue;
1285 }
1286 
1287 /*
1288 =====================
1289 idAnimBlend::SetWeight
1290 =====================
1291 */
1292 void idAnimBlend::SetWeight( float newweight, int currentTime, int blendTime ) {
1293  blendStartValue = GetWeight( currentTime );
1294  blendEndValue = newweight;
1295  blendStartTime = currentTime - 1;
1296  blendDuration = blendTime;
1297 
1298  if ( !newweight ) {
1299  endtime = currentTime + blendTime;
1300  }
1301 }
1302 
1303 /*
1304 =====================
1305 idAnimBlend::NumSyncedAnims
1306 =====================
1307 */
1308 int idAnimBlend::NumSyncedAnims( void ) const {
1309  const idAnim *anim = Anim();
1310  if ( !anim ) {
1311  return 0;
1312  }
1313 
1314  return anim->NumAnims();
1315 }
1316 
1317 /*
1318 =====================
1319 idAnimBlend::SetSyncedAnimWeight
1320 =====================
1321 */
1322 bool idAnimBlend::SetSyncedAnimWeight( int num, float weight ) {
1323  const idAnim *anim = Anim();
1324  if ( !anim ) {
1325  return false;
1326  }
1327 
1328  if ( ( num < 0 ) || ( num > anim->NumAnims() ) ) {
1329  return false;
1330  }
1331 
1332  animWeights[ num ] = weight;
1333  return true;
1334 }
1335 
1336 /*
1337 =====================
1338 idAnimBlend::SetFrame
1339 =====================
1340 */
1341 void idAnimBlend::SetFrame( const idDeclModelDef *modelDef, int _animNum, int _frame, int currentTime, int blendTime ) {
1342  Reset( modelDef );
1343  if ( !modelDef ) {
1344  return;
1345  }
1346 
1347  const idAnim *_anim = modelDef->GetAnim( _animNum );
1348  if ( !_anim ) {
1349  return;
1350  }
1351 
1352  const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1353  if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1354  gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1355  return;
1356  }
1357 
1358  animNum = _animNum;
1359  starttime = currentTime;
1360  endtime = -1;
1361  cycle = -1;
1362  animWeights[ 0 ] = 1.0f;
1363  frame = _frame;
1364 
1365  // a frame of 0 means it's not a single frame blend, so we set it to frame + 1
1366  if ( frame <= 0 ) {
1367  frame = 1;
1368  } else if ( frame > _anim->NumFrames() ) {
1369  frame = _anim->NumFrames();
1370  }
1371 
1372  // set up blend
1373  blendEndValue = 1.0f;
1374  blendStartTime = currentTime - 1;
1375  blendDuration = blendTime;
1376  blendStartValue = 0.0f;
1377 }
1378 
1379 /*
1380 =====================
1381 idAnimBlend::CycleAnim
1382 =====================
1383 */
1384 void idAnimBlend::CycleAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) {
1385  Reset( modelDef );
1386  if ( !modelDef ) {
1387  return;
1388  }
1389 
1390  const idAnim *_anim = modelDef->GetAnim( _animNum );
1391  if ( !_anim ) {
1392  return;
1393  }
1394 
1395  const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1396  if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1397  gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1398  return;
1399  }
1400 
1401  animNum = _animNum;
1402  animWeights[ 0 ] = 1.0f;
1403  endtime = -1;
1404  cycle = -1;
1405  if ( _anim->GetAnimFlags().random_cycle_start ) {
1406  // start the animation at a random time so that characters don't walk in sync
1407  starttime = currentTime - gameLocal.random.RandomFloat() * _anim->Length();
1408  } else {
1409  starttime = currentTime;
1410  }
1411 
1412  // set up blend
1413  blendEndValue = 1.0f;
1414  blendStartTime = currentTime - 1;
1415  blendDuration = blendTime;
1416  blendStartValue = 0.0f;
1417 }
1418 
1419 /*
1420 =====================
1421 idAnimBlend::PlayAnim
1422 =====================
1423 */
1424 void idAnimBlend::PlayAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) {
1425  Reset( modelDef );
1426  if ( !modelDef ) {
1427  return;
1428  }
1429 
1430  const idAnim *_anim = modelDef->GetAnim( _animNum );
1431  if ( !_anim ) {
1432  return;
1433  }
1434 
1435  const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1436  if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1437  gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1438  return;
1439  }
1440 
1441  animNum = _animNum;
1442  starttime = currentTime;
1443  endtime = starttime + _anim->Length();
1444  cycle = 1;
1445  animWeights[ 0 ] = 1.0f;
1446 
1447  // set up blend
1448  blendEndValue = 1.0f;
1449  blendStartTime = currentTime - 1;
1450  blendDuration = blendTime;
1451  blendStartValue = 0.0f;
1452 }
1453 
1454 /*
1455 =====================
1456 idAnimBlend::Clear
1457 =====================
1458 */
1459 void idAnimBlend::Clear( int currentTime, int clearTime ) {
1460  if ( !clearTime ) {
1461  Reset( modelDef );
1462  } else {
1463  SetWeight( 0.0f, currentTime, clearTime );
1464  }
1465 }
1466 
1467 /*
1468 =====================
1469 idAnimBlend::IsDone
1470 =====================
1471 */
1472 bool idAnimBlend::IsDone( int currentTime ) const {
1473  if ( !frame && ( endtime > 0 ) && ( currentTime >= endtime ) ) {
1474  return true;
1475  }
1476 
1477  if ( ( blendEndValue <= 0.0f ) && ( currentTime >= ( blendStartTime + blendDuration ) ) ) {
1478  return true;
1479  }
1480 
1481  return false;
1482 }
1483 
1484 /*
1485 =====================
1486 idAnimBlend::FrameHasChanged
1487 =====================
1488 */
1489 bool idAnimBlend::FrameHasChanged( int currentTime ) const {
1490  // if we don't have an anim, no change
1491  if ( !animNum ) {
1492  return false;
1493  }
1494 
1495  // if anim is done playing, no change
1496  if ( ( endtime > 0 ) && ( currentTime > endtime ) ) {
1497  return false;
1498  }
1499 
1500  // if our blend weight changes, we need to update
1501  if ( ( currentTime < ( blendStartTime + blendDuration ) && ( blendStartValue != blendEndValue ) ) ) {
1502  return true;
1503  }
1504 
1505  // if we're a single frame anim and this isn't the frame we started on, we don't need to update
1506  if ( ( frame || ( NumFrames() == 1 ) ) && ( currentTime != starttime ) ) {
1507  return false;
1508  }
1509 
1510  return true;
1511 }
1512 
1513 /*
1514 =====================
1515 idAnimBlend::GetCycleCount
1516 =====================
1517 */
1518 int idAnimBlend::GetCycleCount( void ) const {
1519  return cycle;
1520 }
1521 
1522 /*
1523 =====================
1524 idAnimBlend::SetCycleCount
1525 =====================
1526 */
1528  const idAnim *anim = Anim();
1529 
1530  if ( !anim ) {
1531  cycle = -1;
1532  endtime = 0;
1533  } else {
1534  cycle = count;
1535  if ( cycle < 0 ) {
1536  cycle = -1;
1537  endtime = -1;
1538  } else if ( cycle == 0 ) {
1539  cycle = 1;
1540 
1541  // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1542  if ( rate == 1.0f ) {
1543  endtime = starttime - timeOffset + anim->Length();
1544  } else if ( rate != 0.0f ) {
1545  endtime = starttime - timeOffset + anim->Length() / rate;
1546  } else {
1547  endtime = -1;
1548  }
1549  } else {
1550  // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1551  if ( rate == 1.0f ) {
1552  endtime = starttime - timeOffset + anim->Length() * cycle;
1553  } else if ( rate != 0.0f ) {
1554  endtime = starttime - timeOffset + ( anim->Length() * cycle ) / rate;
1555  } else {
1556  endtime = -1;
1557  }
1558  }
1559  }
1560 }
1561 
1562 /*
1563 =====================
1564 idAnimBlend::SetPlaybackRate
1565 =====================
1566 */
1567 void idAnimBlend::SetPlaybackRate( int currentTime, float newRate ) {
1568  int animTime;
1569 
1570  if ( rate == newRate ) {
1571  return;
1572  }
1573 
1574  animTime = AnimTime( currentTime );
1575  if ( newRate == 1.0f ) {
1576  timeOffset = animTime - ( currentTime - starttime );
1577  } else {
1578  timeOffset = animTime - ( currentTime - starttime ) * newRate;
1579  }
1580 
1581  rate = newRate;
1582 
1583  // update the anim endtime
1584  SetCycleCount( cycle );
1585 }
1586 
1587 /*
1588 =====================
1589 idAnimBlend::GetPlaybackRate
1590 =====================
1591 */
1592 float idAnimBlend::GetPlaybackRate( void ) const {
1593  return rate;
1594 }
1595 
1596 /*
1597 =====================
1598 idAnimBlend::SetStartTime
1599 =====================
1600 */
1601 void idAnimBlend::SetStartTime( int _startTime ) {
1602  starttime = _startTime;
1603 
1604  // update the anim endtime
1605  SetCycleCount( cycle );
1606 }
1607 
1608 /*
1609 =====================
1610 idAnimBlend::GetStartTime
1611 =====================
1612 */
1613 int idAnimBlend::GetStartTime( void ) const {
1614  if ( !animNum ) {
1615  return 0;
1616  }
1617 
1618  return starttime;
1619 }
1620 
1621 /*
1622 =====================
1623 idAnimBlend::GetEndTime
1624 =====================
1625 */
1626 int idAnimBlend::GetEndTime( void ) const {
1627  if ( !animNum ) {
1628  return 0;
1629  }
1630 
1631  return endtime;
1632 }
1633 
1634 /*
1635 =====================
1636 idAnimBlend::PlayLength
1637 =====================
1638 */
1639 int idAnimBlend::PlayLength( void ) const {
1640  if ( !animNum ) {
1641  return 0;
1642  }
1643 
1644  if ( endtime < 0 ) {
1645  return -1;
1646  }
1647 
1648  return endtime - starttime + timeOffset;
1649 }
1650 
1651 /*
1652 =====================
1653 idAnimBlend::AllowMovement
1654 =====================
1655 */
1656 void idAnimBlend::AllowMovement( bool allow ) {
1657  allowMove = allow;
1658 }
1659 
1660 /*
1661 =====================
1662 idAnimBlend::AllowFrameCommands
1663 =====================
1664 */
1666  allowFrameCommands = allow;
1667 }
1668 
1669 
1670 /*
1671 =====================
1672 idAnimBlend::Anim
1673 =====================
1674 */
1675 const idAnim *idAnimBlend::Anim( void ) const {
1676  if ( !modelDef ) {
1677  return NULL;
1678  }
1679 
1680  const idAnim *anim = modelDef->GetAnim( animNum );
1681  return anim;
1682 }
1683 
1684 /*
1685 =====================
1686 idAnimBlend::AnimNum
1687 =====================
1688 */
1689 int idAnimBlend::AnimNum( void ) const {
1690  return animNum;
1691 }
1692 
1693 /*
1694 =====================
1695 idAnimBlend::AnimTime
1696 =====================
1697 */
1698 int idAnimBlend::AnimTime( int currentTime ) const {
1699  int time;
1700  int length;
1701  const idAnim *anim = Anim();
1702 
1703  if ( anim ) {
1704  if ( frame ) {
1705  return FRAME2MS( frame - 1 );
1706  }
1707 
1708  // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1709  if ( rate == 1.0f ) {
1710  time = currentTime - starttime + timeOffset;
1711  } else {
1712  time = static_cast<int>( ( currentTime - starttime ) * rate ) + timeOffset;
1713  }
1714 
1715  // given enough time, we can easily wrap time around in our frame calculations, so
1716  // keep cycling animations' time within the length of the anim.
1717  length = anim->Length();
1718  if ( ( cycle < 0 ) && ( length > 0 ) ) {
1719  time %= length;
1720 
1721  // time will wrap after 24 days (oh no!), resulting in negative results for the %.
1722  // adding the length gives us the proper result.
1723  if ( time < 0 ) {
1724  time += length;
1725  }
1726  }
1727  return time;
1728  } else {
1729  return 0;
1730  }
1731 }
1732 
1733 /*
1734 =====================
1735 idAnimBlend::GetFrameNumber
1736 =====================
1737 */
1738 int idAnimBlend::GetFrameNumber( int currentTime ) const {
1739  const idMD5Anim *md5anim;
1740  frameBlend_t frameinfo;
1741  int animTime;
1742 
1743  const idAnim *anim = Anim();
1744  if ( !anim ) {
1745  return 1;
1746  }
1747 
1748  if ( frame ) {
1749  return frame;
1750  }
1751 
1752  md5anim = anim->MD5Anim( 0 );
1753  animTime = AnimTime( currentTime );
1754  md5anim->ConvertTimeToFrame( animTime, cycle, frameinfo );
1755 
1756  return frameinfo.frame1 + 1;
1757 }
1758 
1759 /*
1760 =====================
1761 idAnimBlend::CallFrameCommands
1762 =====================
1763 */
1764 void idAnimBlend::CallFrameCommands( idEntity *ent, int fromtime, int totime ) const {
1765  const idMD5Anim *md5anim;
1766  frameBlend_t frame1;
1767  frameBlend_t frame2;
1768  int fromFrameTime;
1769  int toFrameTime;
1770 
1771  if ( !allowFrameCommands || !ent || frame || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
1772  return;
1773  }
1774 
1775  const idAnim *anim = Anim();
1776  if ( !anim || !anim->HasFrameCommands() ) {
1777  return;
1778  }
1779 
1780  if ( totime <= starttime ) {
1781  // don't play until next frame or we'll play commands twice.
1782  // this happens on the player sometimes.
1783  return;
1784  }
1785 
1786  fromFrameTime = AnimTime( fromtime );
1787  toFrameTime = AnimTime( totime );
1788  if ( toFrameTime < fromFrameTime ) {
1789  toFrameTime += anim->Length();
1790  }
1791 
1792  md5anim = anim->MD5Anim( 0 );
1793  md5anim->ConvertTimeToFrame( fromFrameTime, cycle, frame1 );
1794  md5anim->ConvertTimeToFrame( toFrameTime, cycle, frame2 );
1795 
1796  if ( fromFrameTime <= 0 ) {
1797  // make sure first frame is called
1798  anim->CallFrameCommands( ent, -1, frame2.frame1 );
1799  } else {
1800  anim->CallFrameCommands( ent, frame1.frame1, frame2.frame1 );
1801  }
1802 }
1803 
1804 /*
1805 =====================
1806 idAnimBlend::BlendAnim
1807 =====================
1808 */
1809 bool idAnimBlend::BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOriginOffset, bool overrideBlend, bool printInfo ) const {
1810  int i;
1811  float lerp;
1812  float mixWeight;
1813  const idMD5Anim *md5anim;
1814  idJointQuat *ptr;
1815  frameBlend_t frametime;
1816  idJointQuat *jointFrame;
1817  idJointQuat *mixFrame;
1818  int numAnims;
1819  int time;
1820 
1821  const idAnim *anim = Anim();
1822  if ( !anim ) {
1823  return false;
1824  }
1825 
1826  float weight = GetWeight( currentTime );
1827  if ( blendWeight > 0.0f ) {
1828  if ( ( endtime >= 0 ) && ( currentTime >= endtime ) ) {
1829  return false;
1830  }
1831  if ( !weight ) {
1832  return false;
1833  }
1834  if ( overrideBlend ) {
1835  blendWeight = 1.0f - weight;
1836  }
1837  }
1838 
1839  if ( ( channel == ANIMCHANNEL_ALL ) && !blendWeight ) {
1840  // we don't need a temporary buffer, so just store it directly in the blend frame
1841  jointFrame = blendFrame;
1842  } else {
1843  // allocate a temporary buffer to copy the joints from
1844  jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
1845  }
1846 
1847  time = AnimTime( currentTime );
1848 
1849  numAnims = anim->NumAnims();
1850  if ( numAnims == 1 ) {
1851  md5anim = anim->MD5Anim( 0 );
1852  if ( frame ) {
1853  md5anim->GetSingleFrame( frame - 1, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1854  } else {
1855  md5anim->ConvertTimeToFrame( time, cycle, frametime );
1856  md5anim->GetInterpolatedFrame( frametime, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1857  }
1858  } else {
1859  //
1860  // need to mix the multipoint anim together first
1861  //
1862  // allocate a temporary buffer to copy the joints to
1863  mixFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
1864 
1865  if ( !frame ) {
1866  anim->MD5Anim( 0 )->ConvertTimeToFrame( time, cycle, frametime );
1867  }
1868 
1869  ptr = jointFrame;
1870  mixWeight = 0.0f;
1871  for( i = 0; i < numAnims; i++ ) {
1872  if ( animWeights[ i ] > 0.0f ) {
1873  mixWeight += animWeights[ i ];
1874  lerp = animWeights[ i ] / mixWeight;
1875  md5anim = anim->MD5Anim( i );
1876  if ( frame ) {
1877  md5anim->GetSingleFrame( frame - 1, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1878  } else {
1879  md5anim->GetInterpolatedFrame( frametime, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1880  }
1881 
1882  // only blend after the first anim is mixed in
1883  if ( ptr != jointFrame ) {
1884  SIMDProcessor->BlendJoints( jointFrame, ptr, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1885  }
1886 
1887  ptr = mixFrame;
1888  }
1889  }
1890 
1891  if ( !mixWeight ) {
1892  return false;
1893  }
1894  }
1895 
1896  if ( removeOriginOffset ) {
1897  if ( allowMove ) {
1898 #ifdef VELOCITY_MOVE
1899  jointFrame[ 0 ].t.x = 0.0f;
1900 #else
1901  jointFrame[ 0 ].t.Zero();
1902 #endif
1903  }
1904 
1905  if ( anim->GetAnimFlags().anim_turn ) {
1906  jointFrame[ 0 ].q.Set( -0.70710677f, 0.0f, 0.0f, 0.70710677f );
1907  }
1908  }
1909 
1910  if ( !blendWeight ) {
1911  blendWeight = weight;
1912  if ( channel != ANIMCHANNEL_ALL ) {
1913  const int *index = modelDef->GetChannelJoints( channel );
1914  const int num = modelDef->NumJointsOnChannel( channel );
1915  for( i = 0; i < num; i++ ) {
1916  int j = index[i];
1917  blendFrame[j].t = jointFrame[j].t;
1918  blendFrame[j].q = jointFrame[j].q;
1919  }
1920  }
1921  } else {
1922  blendWeight += weight;
1923  lerp = weight / blendWeight;
1924  SIMDProcessor->BlendJoints( blendFrame, jointFrame, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1925  }
1926 
1927  if ( printInfo ) {
1928  if ( frame ) {
1929  gameLocal.Printf( " %s: '%s', %d, %.2f%%\n", channelNames[ channel ], anim->FullName(), frame, weight * 100.0f );
1930  } else {
1931  gameLocal.Printf( " %s: '%s', %.3f, %.2f%%\n", channelNames[ channel ], anim->FullName(), ( float )frametime.frame1 + frametime.backlerp, weight * 100.0f );
1932  }
1933  }
1934 
1935  return true;
1936 }
1937 
1938 /*
1939 =====================
1940 idAnimBlend::BlendOrigin
1941 =====================
1942 */
1943 void idAnimBlend::BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const {
1944  float lerp;
1945  idVec3 animpos;
1946  idVec3 pos;
1947  int time;
1948  int num;
1949  int i;
1950 
1951  if ( frame || ( ( endtime > 0 ) && ( currentTime > endtime ) ) ) {
1952  return;
1953  }
1954 
1955  const idAnim *anim = Anim();
1956  if ( !anim ) {
1957  return;
1958  }
1959 
1960  if ( allowMove && removeOriginOffset ) {
1961  return;
1962  }
1963 
1964  float weight = GetWeight( currentTime );
1965  if ( !weight ) {
1966  return;
1967  }
1968 
1969  time = AnimTime( currentTime );
1970 
1971  pos.Zero();
1972  num = anim->NumAnims();
1973  for( i = 0; i < num; i++ ) {
1974  anim->GetOrigin( animpos, i, time, cycle );
1975  pos += animpos * animWeights[ i ];
1976  }
1977 
1978  if ( !blendWeight ) {
1979  blendPos = pos;
1980  blendWeight = weight;
1981  } else {
1982  lerp = weight / ( blendWeight + weight );
1983  blendPos += lerp * ( pos - blendPos );
1984  blendWeight += weight;
1985  }
1986 }
1987 
1988 /*
1989 =====================
1990 idAnimBlend::BlendDelta
1991 =====================
1992 */
1993 void idAnimBlend::BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const {
1994  idVec3 pos1;
1995  idVec3 pos2;
1996  idVec3 animpos;
1997  idVec3 delta;
1998  int time1;
1999  int time2;
2000  float lerp;
2001  int num;
2002  int i;
2003 
2004  if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
2005  return;
2006  }
2007 
2008  const idAnim *anim = Anim();
2009  if ( !anim ) {
2010  return;
2011  }
2012 
2013  float weight = GetWeight( totime );
2014  if ( !weight ) {
2015  return;
2016  }
2017 
2018  time1 = AnimTime( fromtime );
2019  time2 = AnimTime( totime );
2020  if ( time2 < time1 ) {
2021  time2 += anim->Length();
2022  }
2023 
2024  num = anim->NumAnims();
2025 
2026  pos1.Zero();
2027  pos2.Zero();
2028  for( i = 0; i < num; i++ ) {
2029  anim->GetOrigin( animpos, i, time1, cycle );
2030  pos1 += animpos * animWeights[ i ];
2031 
2032  anim->GetOrigin( animpos, i, time2, cycle );
2033  pos2 += animpos * animWeights[ i ];
2034  }
2035 
2036  delta = pos2 - pos1;
2037  if ( !blendWeight ) {
2038  blendDelta = delta;
2039  blendWeight = weight;
2040  } else {
2041  lerp = weight / ( blendWeight + weight );
2042  blendDelta += lerp * ( delta - blendDelta );
2043  blendWeight += weight;
2044  }
2045 }
2046 
2047 /*
2048 =====================
2049 idAnimBlend::BlendDeltaRotation
2050 =====================
2051 */
2052 void idAnimBlend::BlendDeltaRotation( int fromtime, int totime, idQuat &blendDelta, float &blendWeight ) const {
2053  idQuat q1;
2054  idQuat q2;
2055  idQuat q3;
2056  int time1;
2057  int time2;
2058  float lerp;
2059  float mixWeight;
2060  int num;
2061  int i;
2062 
2063  if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
2064  return;
2065  }
2066 
2067  const idAnim *anim = Anim();
2068  if ( !anim || !anim->GetAnimFlags().anim_turn ) {
2069  return;
2070  }
2071 
2072  float weight = GetWeight( totime );
2073  if ( !weight ) {
2074  return;
2075  }
2076 
2077  time1 = AnimTime( fromtime );
2078  time2 = AnimTime( totime );
2079  if ( time2 < time1 ) {
2080  time2 += anim->Length();
2081  }
2082 
2083  q1.Set( 0.0f, 0.0f, 0.0f, 1.0f );
2084  q2.Set( 0.0f, 0.0f, 0.0f, 1.0f );
2085 
2086  mixWeight = 0.0f;
2087  num = anim->NumAnims();
2088  for( i = 0; i < num; i++ ) {
2089  if ( animWeights[ i ] > 0.0f ) {
2090  mixWeight += animWeights[ i ];
2091  if ( animWeights[ i ] == mixWeight ) {
2092  anim->GetOriginRotation( q1, i, time1, cycle );
2093  anim->GetOriginRotation( q2, i, time2, cycle );
2094  } else {
2095  lerp = animWeights[ i ] / mixWeight;
2096  anim->GetOriginRotation( q3, i, time1, cycle );
2097  q1.Slerp( q1, q3, lerp );
2098 
2099  anim->GetOriginRotation( q3, i, time2, cycle );
2100  q2.Slerp( q1, q3, lerp );
2101  }
2102  }
2103  }
2104 
2105  q3 = q1.Inverse() * q2;
2106  if ( !blendWeight ) {
2107  blendDelta = q3;
2108  blendWeight = weight;
2109  } else {
2110  lerp = weight / ( blendWeight + weight );
2111  blendDelta.Slerp( blendDelta, q3, lerp );
2112  blendWeight += weight;
2113  }
2114 }
2115 
2116 /*
2117 =====================
2118 idAnimBlend::AddBounds
2119 =====================
2120 */
2121 bool idAnimBlend::AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const {
2122  int i;
2123  int num;
2124  idBounds b;
2125  int time;
2126  idVec3 pos;
2127  bool addorigin;
2128 
2129  if ( ( endtime > 0 ) && ( currentTime > endtime ) ) {
2130  return false;
2131  }
2132 
2133  const idAnim *anim = Anim();
2134  if ( !anim ) {
2135  return false;
2136  }
2137 
2138  float weight = GetWeight( currentTime );
2139  if ( !weight ) {
2140  return false;
2141  }
2142 
2143  time = AnimTime( currentTime );
2144  num = anim->NumAnims();
2145 
2146  addorigin = !allowMove || !removeOriginOffset;
2147  for( i = 0; i < num; i++ ) {
2148  if ( anim->GetBounds( b, i, time, cycle ) ) {
2149  if ( addorigin ) {
2150  anim->GetOrigin( pos, i, time, cycle );
2151  b.TranslateSelf( pos );
2152  }
2153  bounds.AddBounds( b );
2154  }
2155  }
2156 
2157  return true;
2158 }
2159 
2160 /***********************************************************************
2161 
2162  idDeclModelDef
2163 
2164 ***********************************************************************/
2165 
2166 /*
2167 =====================
2168 idDeclModelDef::idDeclModelDef
2169 =====================
2170 */
2172  modelHandle = NULL;
2173  skin = NULL;
2174  offset.Zero();
2175  for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) {
2176  channelJoints[i].Clear();
2177  }
2178 }
2179 
2180 /*
2181 =====================
2182 idDeclModelDef::~idDeclModelDef
2183 =====================
2184 */
2186  FreeData();
2187 }
2188 
2189 /*
2190 =================
2191 idDeclModelDef::Size
2192 =================
2193 */
2194 size_t idDeclModelDef::Size( void ) const {
2195  return sizeof( idDeclModelDef );
2196 }
2197 
2198 /*
2199 =====================
2200 idDeclModelDef::CopyDecl
2201 =====================
2202 */
2204  int i;
2205 
2206  FreeData();
2207 
2208  offset = decl->offset;
2209  modelHandle = decl->modelHandle;
2210  skin = decl->skin;
2211 
2212  anims.SetNum( decl->anims.Num() );
2213  for( i = 0; i < anims.Num(); i++ ) {
2214  anims[ i ] = new idAnim( this, decl->anims[ i ] );
2215  }
2216 
2217  joints.SetNum( decl->joints.Num() );
2218  memcpy( joints.Ptr(), decl->joints.Ptr(), decl->joints.Num() * sizeof( joints[0] ) );
2219  jointParents.SetNum( decl->jointParents.Num() );
2220  memcpy( jointParents.Ptr(), decl->jointParents.Ptr(), decl->jointParents.Num() * sizeof( jointParents[0] ) );
2221  for ( i = 0; i < ANIM_NumAnimChannels; i++ ) {
2222  channelJoints[i] = decl->channelJoints[i];
2223  }
2224 }
2225 
2226 /*
2227 =====================
2228 idDeclModelDef::FreeData
2229 =====================
2230 */
2232  anims.DeleteContents( true );
2233  joints.Clear();
2234  jointParents.Clear();
2235  modelHandle = NULL;
2236  skin = NULL;
2237  offset.Zero();
2238  for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) {
2239  channelJoints[i].Clear();
2240  }
2241 }
2242 
2243 /*
2244 ================
2245 idDeclModelDef::DefaultDefinition
2246 ================
2247 */
2248 const char *idDeclModelDef::DefaultDefinition( void ) const {
2249  return "{ }";
2250 }
2251 
2252 /*
2253 ====================
2254 idDeclModelDef::FindJoint
2255 ====================
2256 */
2257 const jointInfo_t *idDeclModelDef::FindJoint( const char *name ) const {
2258  int i;
2259  const idMD5Joint *joint;
2260 
2261  if ( !modelHandle ) {
2262  return NULL;
2263  }
2264 
2265  joint = modelHandle->GetJoints();
2266  for( i = 0; i < joints.Num(); i++, joint++ ) {
2267  if ( !joint->name.Icmp( name ) ) {
2268  return &joints[ i ];
2269  }
2270  }
2271 
2272  return NULL;
2273 }
2274 
2275 /*
2276 =====================
2277 idDeclModelDef::ModelHandle
2278 =====================
2279 */
2281  return ( idRenderModel * )modelHandle;
2282 }
2283 
2284 /*
2285 =====================
2286 idDeclModelDef::GetJointList
2287 =====================
2288 */
2289 void idDeclModelDef::GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const {
2290  const char *pos;
2291  idStr jointname;
2292  const jointInfo_t *joint;
2293  const jointInfo_t *child;
2294  int i;
2295  int num;
2296  bool getChildren;
2297  bool subtract;
2298 
2299  if ( !modelHandle ) {
2300  return;
2301  }
2302 
2303  jointList.Clear();
2304 
2305  num = modelHandle->NumJoints();
2306 
2307  // scan through list of joints and add each to the joint list
2308  pos = jointnames;
2309  while( *pos ) {
2310  // skip over whitespace
2311  while( ( *pos != 0 ) && isspace( *pos ) ) {
2312  pos++;
2313  }
2314 
2315  if ( !*pos ) {
2316  // no more names
2317  break;
2318  }
2319 
2320  // copy joint name
2321  jointname = "";
2322 
2323  if ( *pos == '-' ) {
2324  subtract = true;
2325  pos++;
2326  } else {
2327  subtract = false;
2328  }
2329 
2330  if ( *pos == '*' ) {
2331  getChildren = true;
2332  pos++;
2333  } else {
2334  getChildren = false;
2335  }
2336 
2337  while( ( *pos != 0 ) && !isspace( *pos ) ) {
2338  jointname += *pos;
2339  pos++;
2340  }
2341 
2342  joint = FindJoint( jointname );
2343  if ( !joint ) {
2344  gameLocal.Warning( "Unknown joint '%s' in '%s' for model '%s'", jointname.c_str(), jointnames, GetName() );
2345  continue;
2346  }
2347 
2348  if ( !subtract ) {
2349  jointList.AddUnique( joint->num );
2350  } else {
2351  jointList.Remove( joint->num );
2352  }
2353 
2354  if ( getChildren ) {
2355  // include all joint's children
2356  child = joint + 1;
2357  for( i = joint->num + 1; i < num; i++, child++ ) {
2358  // all children of the joint should follow it in the list.
2359  // once we reach a joint without a parent or with a parent
2360  // who is earlier in the list than the specified joint, then
2361  // we've gone through all it's children.
2362  if ( child->parentNum < joint->num ) {
2363  break;
2364  }
2365 
2366  if ( !subtract ) {
2367  jointList.AddUnique( child->num );
2368  } else {
2369  jointList.Remove( child->num );
2370  }
2371  }
2372  }
2373  }
2374 }
2375 
2376 /*
2377 =====================
2378 idDeclModelDef::Touch
2379 =====================
2380 */
2381 void idDeclModelDef::Touch( void ) const {
2382  if ( modelHandle ) {
2384  }
2385 }
2386 
2387 /*
2388 =====================
2389 idDeclModelDef::GetDefaultSkin
2390 =====================
2391 */
2393  return skin;
2394 }
2395 
2396 /*
2397 =====================
2398 idDeclModelDef::GetDefaultPose
2399 =====================
2400 */
2402  return modelHandle->GetDefaultPose();
2403 }
2404 
2405 /*
2406 =====================
2407 idDeclModelDef::SetupJoints
2408 =====================
2409 */
2410 void idDeclModelDef::SetupJoints( int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset ) const {
2411  int num;
2412  const idJointQuat *pose;
2413  idJointMat *list;
2414 
2415  if ( !modelHandle || modelHandle->IsDefaultModel() ) {
2416  Mem_Free16( (*jointList) );
2417  (*jointList) = NULL;
2418  frameBounds.Clear();
2419  return;
2420  }
2421 
2422  // get the number of joints
2423  num = modelHandle->NumJoints();
2424 
2425  if ( !num ) {
2426  gameLocal.Error( "model '%s' has no joints", modelHandle->Name() );
2427  }
2428 
2429  // set up initial pose for model (with no pose, model is just a jumbled mess)
2430  list = (idJointMat *) Mem_Alloc16( num * sizeof( list[0] ) );
2431  pose = GetDefaultPose();
2432 
2433  // convert the joint quaternions to joint matrices
2435 
2436  // check if we offset the model by the origin joint
2437  if ( removeOriginOffset ) {
2438 #ifdef VELOCITY_MOVE
2439  list[ 0 ].SetTranslation( idVec3( offset.x, offset.y + pose[0].t.y, offset.z + pose[0].t.z ) );
2440 #else
2441  list[ 0 ].SetTranslation( offset );
2442 #endif
2443  } else {
2444  list[ 0 ].SetTranslation( pose[0].t + offset );
2445  }
2446 
2447  // transform the joint hierarchy
2448  SIMDProcessor->TransformJoints( list, jointParents.Ptr(), 1, joints.Num() - 1 );
2449 
2450  *numJoints = num;
2451  *jointList = list;
2452 
2453  // get the bounds of the default pose
2454  frameBounds = modelHandle->Bounds( NULL );
2455 }
2456 
2457 /*
2458 =====================
2459 idDeclModelDef::ParseAnim
2460 =====================
2461 */
2462 bool idDeclModelDef::ParseAnim( idLexer &src, int numDefaultAnims ) {
2463  int i;
2464  int len;
2465  idAnim *anim;
2466  const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ];
2467  const idMD5Anim *md5anim;
2468  idStr alias;
2469  idToken realname;
2470  idToken token;
2471  int numAnims;
2472  animFlags_t flags;
2473 
2474  numAnims = 0;
2475  memset( md5anims, 0, sizeof( md5anims ) );
2476 
2477  if( !src.ReadToken( &realname ) ) {
2478  src.Warning( "Unexpected end of file" );
2479  MakeDefault();
2480  return false;
2481  }
2482  alias = realname;
2483 
2484  for( i = 0; i < anims.Num(); i++ ) {
2485  if ( !strcmp( anims[ i ]->FullName(), realname ) ) {
2486  break;
2487  }
2488  }
2489 
2490  if ( ( i < anims.Num() ) && ( i >= numDefaultAnims ) ) {
2491  src.Warning( "Duplicate anim '%s'", realname.c_str() );
2492  MakeDefault();
2493  return false;
2494  }
2495 
2496  if ( i < numDefaultAnims ) {
2497  anim = anims[ i ];
2498  } else {
2499  // create the alias associated with this animation
2500  anim = new idAnim();
2501  anims.Append( anim );
2502  }
2503 
2504  // random anims end with a number. find the numeric suffix of the animation.
2505  len = alias.Length();
2506  for( i = len - 1; i > 0; i-- ) {
2507  if ( !isdigit( alias[ i ] ) ) {
2508  break;
2509  }
2510  }
2511 
2512  // check for zero length name, or a purely numeric name
2513  if ( i <= 0 ) {
2514  src.Warning( "Invalid animation name '%s'", alias.c_str() );
2515  MakeDefault();
2516  return false;
2517  }
2518 
2519  // remove the numeric suffix
2520  alias.CapLength( i + 1 );
2521 
2522  // parse the anims from the string
2523  do {
2524  if( !src.ReadToken( &token ) ) {
2525  src.Warning( "Unexpected end of file" );
2526  MakeDefault();
2527  return false;
2528  }
2529 
2530  // lookup the animation
2531  md5anim = animationLib.GetAnim( token );
2532  if ( !md5anim ) {
2533  src.Warning( "Couldn't load anim '%s'", token.c_str() );
2534  MakeDefault();
2535  return false;
2536  }
2537 
2538  md5anim->CheckModelHierarchy( modelHandle );
2539 
2540  if ( numAnims > 0 ) {
2541  // make sure it's the same length as the other anims
2542  if ( md5anim->Length() != md5anims[ 0 ]->Length() ) {
2543  src.Warning( "Anim '%s' does not match length of anim '%s'", md5anim->Name(), md5anims[ 0 ]->Name() );
2544  MakeDefault();
2545  return false;
2546  }
2547  }
2548 
2549  if ( numAnims >= ANIM_MaxSyncedAnims ) {
2550  src.Warning( "Exceeded max synced anims (%d)", ANIM_MaxSyncedAnims );
2551  MakeDefault();
2552  return false;
2553  }
2554 
2555  // add it to our list
2556  md5anims[ numAnims ] = md5anim;
2557  numAnims++;
2558  } while ( src.CheckTokenString( "," ) );
2559 
2560  if ( !numAnims ) {
2561  src.Warning( "No animation specified" );
2562  MakeDefault();
2563  return false;
2564  }
2565 
2566  anim->SetAnim( this, realname, alias, numAnims, md5anims );
2567  memset( &flags, 0, sizeof( flags ) );
2568 
2569  // parse any frame commands or animflags
2570  if ( src.CheckTokenString( "{" ) ) {
2571  while( 1 ) {
2572  if( !src.ReadToken( &token ) ) {
2573  src.Warning( "Unexpected end of file" );
2574  MakeDefault();
2575  return false;
2576  }
2577  if ( token == "}" ) {
2578  break;
2579  }else if ( token == "prevent_idle_override" ) {
2580  flags.prevent_idle_override = true;
2581  } else if ( token == "random_cycle_start" ) {
2582  flags.random_cycle_start = true;
2583  } else if ( token == "ai_no_turn" ) {
2584  flags.ai_no_turn = true;
2585  } else if ( token == "anim_turn" ) {
2586  flags.anim_turn = true;
2587  } else if ( token == "frame" ) {
2588  // create a frame command
2589  int framenum;
2590  const char *err;
2591 
2592  // make sure we don't have any line breaks while reading the frame command so the error line # will be correct
2593  if ( !src.ReadTokenOnLine( &token ) ) {
2594  src.Warning( "Missing frame # after 'frame'" );
2595  MakeDefault();
2596  return false;
2597  }
2598  if ( token.type == TT_PUNCTUATION && token == "-" ) {
2599  src.Warning( "Invalid frame # after 'frame'" );
2600  MakeDefault();
2601  return false;
2602  } else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
2603  src.Error( "expected integer value, found '%s'", token.c_str() );
2604  }
2605 
2606  // get the frame number
2607  framenum = token.GetIntValue();
2608 
2609  // put the command on the specified frame of the animation
2610  err = anim->AddFrameCommand( this, framenum, src, NULL );
2611  if ( err ) {
2612  src.Warning( "%s", err );
2613  MakeDefault();
2614  return false;
2615  }
2616  } else {
2617  src.Warning( "Unknown command '%s'", token.c_str() );
2618  MakeDefault();
2619  return false;
2620  }
2621  }
2622  }
2623 
2624  // set the flags
2625  anim->SetAnimFlags( flags );
2626  return true;
2627 }
2628 
2629 /*
2630 ================
2631 idDeclModelDef::Parse
2632 ================
2633 */
2634 bool idDeclModelDef::Parse( const char *text, const int textLength ) {
2635  int i;
2636  int num;
2637  idStr filename;
2638  idStr extension;
2639  const idMD5Joint *md5joint;
2640  const idMD5Joint *md5joints;
2641  idLexer src;
2642  idToken token;
2643  idToken token2;
2644  idStr jointnames;
2645  int channel;
2646  jointHandle_t jointnum;
2647  idList<jointHandle_t> jointList;
2648  int numDefaultAnims;
2649 
2650  src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
2651  src.SetFlags( DECL_LEXER_FLAGS );
2652  src.SkipUntilString( "{" );
2653 
2654  numDefaultAnims = 0;
2655  while( 1 ) {
2656  if ( !src.ReadToken( &token ) ) {
2657  break;
2658  }
2659 
2660  if ( !token.Icmp( "}" ) ) {
2661  break;
2662  }
2663 
2664  if ( token == "inherit" ) {
2665  if( !src.ReadToken( &token2 ) ) {
2666  src.Warning( "Unexpected end of file" );
2667  MakeDefault();
2668  return false;
2669  }
2670 
2671  const idDeclModelDef *copy = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, token2, false ) );
2672  if ( !copy ) {
2673  common->Warning( "Unknown model definition '%s'", token2.c_str() );
2674  } else if ( copy->GetState() == DS_DEFAULTED ) {
2675  common->Warning( "inherited model definition '%s' defaulted", token2.c_str() );
2676  MakeDefault();
2677  return false;
2678  } else {
2679  CopyDecl( copy );
2680  numDefaultAnims = anims.Num();
2681  }
2682  } else if ( token == "skin" ) {
2683  if( !src.ReadToken( &token2 ) ) {
2684  src.Warning( "Unexpected end of file" );
2685  MakeDefault();
2686  return false;
2687  }
2688  skin = declManager->FindSkin( token2 );
2689  if ( !skin ) {
2690  src.Warning( "Skin '%s' not found", token2.c_str() );
2691  MakeDefault();
2692  return false;
2693  }
2694  } else if ( token == "mesh" ) {
2695  if( !src.ReadToken( &token2 ) ) {
2696  src.Warning( "Unexpected end of file" );
2697  MakeDefault();
2698  return false;
2699  }
2700  filename = token2;
2701  filename.ExtractFileExtension( extension );
2702  if ( extension != MD5_MESH_EXT ) {
2703  src.Warning( "Invalid model for MD5 mesh" );
2704  MakeDefault();
2705  return false;
2706  }
2707  modelHandle = renderModelManager->FindModel( filename );
2708  if ( !modelHandle ) {
2709  src.Warning( "Model '%s' not found", filename.c_str() );
2710  MakeDefault();
2711  return false;
2712  }
2713 
2714  if ( modelHandle->IsDefaultModel() ) {
2715  src.Warning( "Model '%s' defaulted", filename.c_str() );
2716  MakeDefault();
2717  return false;
2718  }
2719 
2720  // get the number of joints
2721  num = modelHandle->NumJoints();
2722  if ( !num ) {
2723  src.Warning( "Model '%s' has no joints", filename.c_str() );
2724  }
2725 
2726  // set up the joint hierarchy
2727  joints.SetGranularity( 1 );
2728  joints.SetNum( num );
2729  jointParents.SetNum( num );
2730  channelJoints[0].SetNum( num );
2731  md5joints = modelHandle->GetJoints();
2732  md5joint = md5joints;
2733  for( i = 0; i < num; i++, md5joint++ ) {
2734  joints[i].channel = ANIMCHANNEL_ALL;
2735  joints[i].num = static_cast<jointHandle_t>( i );
2736  if ( md5joint->parent ) {
2737  joints[i].parentNum = static_cast<jointHandle_t>( md5joint->parent - md5joints );
2738  } else {
2739  joints[i].parentNum = INVALID_JOINT;
2740  }
2741  jointParents[i] = joints[i].parentNum;
2742  channelJoints[0][i] = i;
2743  }
2744  } else if ( token == "remove" ) {
2745  // removes any anims whos name matches
2746  if( !src.ReadToken( &token2 ) ) {
2747  src.Warning( "Unexpected end of file" );
2748  MakeDefault();
2749  return false;
2750  }
2751  num = 0;
2752  for( i = 0; i < anims.Num(); i++ ) {
2753  if ( ( token2 == anims[ i ]->Name() ) || ( token2 == anims[ i ]->FullName() ) ) {
2754  delete anims[ i ];
2755  anims.RemoveIndex( i );
2756  if ( i >= numDefaultAnims ) {
2757  src.Warning( "Anim '%s' was not inherited. Anim should be removed from the model def.", token2.c_str() );
2758  MakeDefault();
2759  return false;
2760  }
2761  i--;
2762  numDefaultAnims--;
2763  num++;
2764  continue;
2765  }
2766  }
2767  if ( !num ) {
2768  src.Warning( "Couldn't find anim '%s' to remove", token2.c_str() );
2769  MakeDefault();
2770  return false;
2771  }
2772  } else if ( token == "anim" ) {
2773  if ( !modelHandle ) {
2774  src.Warning( "Must specify mesh before defining anims" );
2775  MakeDefault();
2776  return false;
2777  }
2778  if ( !ParseAnim( src, numDefaultAnims ) ) {
2779  MakeDefault();
2780  return false;
2781  }
2782  } else if ( token == "offset" ) {
2783  if ( !src.Parse1DMatrix( 3, offset.ToFloatPtr() ) ) {
2784  src.Warning( "Expected vector following 'offset'" );
2785  MakeDefault();
2786  return false;
2787  }
2788  } else if ( token == "channel" ) {
2789  if ( !modelHandle ) {
2790  src.Warning( "Must specify mesh before defining channels" );
2791  MakeDefault();
2792  return false;
2793  }
2794 
2795  // set the channel for a group of joints
2796  if( !src.ReadToken( &token2 ) ) {
2797  src.Warning( "Unexpected end of file" );
2798  MakeDefault();
2799  return false;
2800  }
2801  if ( !src.CheckTokenString( "(" ) ) {
2802  src.Warning( "Expected { after '%s'\n", token2.c_str() );
2803  MakeDefault();
2804  return false;
2805  }
2806 
2807  for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) {
2808  if ( !idStr::Icmp( channelNames[ i ], token2 ) ) {
2809  break;
2810  }
2811  }
2812 
2813  if ( i >= ANIM_NumAnimChannels ) {
2814  src.Warning( "Unknown channel '%s'", token2.c_str() );
2815  MakeDefault();
2816  return false;
2817  }
2818 
2819  channel = i;
2820  jointnames = "";
2821 
2822  while( !src.CheckTokenString( ")" ) ) {
2823  if( !src.ReadToken( &token2 ) ) {
2824  src.Warning( "Unexpected end of file" );
2825  MakeDefault();
2826  return false;
2827  }
2828  jointnames += token2;
2829  if ( ( token2 != "*" ) && ( token2 != "-" ) ) {
2830  jointnames += " ";
2831  }
2832  }
2833 
2834  GetJointList( jointnames, jointList );
2835 
2836  channelJoints[ channel ].SetNum( jointList.Num() );
2837  for( num = i = 0; i < jointList.Num(); i++ ) {
2838  jointnum = jointList[ i ];
2839  if ( joints[ jointnum ].channel != ANIMCHANNEL_ALL ) {
2840  src.Warning( "Joint '%s' assigned to multiple channels", modelHandle->GetJointName( jointnum ) );
2841  continue;
2842  }
2843  joints[ jointnum ].channel = channel;
2844  channelJoints[ channel ][ num++ ] = jointnum;
2845  }
2846  channelJoints[ channel ].SetNum( num );
2847  } else {
2848  src.Warning( "unknown token '%s'", token.c_str() );
2849  MakeDefault();
2850  return false;
2851  }
2852  }
2853 
2854  // shrink the anim list down to save space
2855  anims.SetGranularity( 1 );
2856  anims.SetNum( anims.Num() );
2857 
2858  return true;
2859 }
2860 
2861 /*
2862 =====================
2863 idDeclModelDef::HasAnim
2864 =====================
2865 */
2866 bool idDeclModelDef::HasAnim( const char *name ) const {
2867  int i;
2868 
2869  // find any animations with same name
2870  for( i = 0; i < anims.Num(); i++ ) {
2871  if ( !strcmp( anims[ i ]->Name(), name ) ) {
2872  return true;
2873  }
2874  }
2875 
2876  return false;
2877 }
2878 
2879 /*
2880 =====================
2881 idDeclModelDef::NumAnims
2882 =====================
2883 */
2884 int idDeclModelDef::NumAnims( void ) const {
2885  return anims.Num() + 1;
2886 }
2887 
2888 /*
2889 =====================
2890 idDeclModelDef::GetSpecificAnim
2891 
2892 Gets the exact anim for the name, without randomization.
2893 =====================
2894 */
2895 int idDeclModelDef::GetSpecificAnim( const char *name ) const {
2896  int i;
2897 
2898  // find a specific animation
2899  for( i = 0; i < anims.Num(); i++ ) {
2900  if ( !strcmp( anims[ i ]->FullName(), name ) ) {
2901  return i + 1;
2902  }
2903  }
2904 
2905  // didn't find it
2906  return 0;
2907 }
2908 
2909 /*
2910 =====================
2911 idDeclModelDef::GetAnim
2912 =====================
2913 */
2914 const idAnim *idDeclModelDef::GetAnim( int index ) const {
2915  if ( ( index < 1 ) || ( index > anims.Num() ) ) {
2916  return NULL;
2917  }
2918 
2919  return anims[ index - 1 ];
2920 }
2921 
2922 /*
2923 =====================
2924 idDeclModelDef::GetAnim
2925 =====================
2926 */
2927 int idDeclModelDef::GetAnim( const char *name ) const {
2928  int i;
2929  int which;
2930  const int MAX_ANIMS = 64;
2931  int animList[ MAX_ANIMS ];
2932  int numAnims;
2933  int len;
2934 
2935  len = strlen( name );
2936  if ( len && idStr::CharIsNumeric( name[ len - 1 ] ) ) {
2937  // find a specific animation
2938  return GetSpecificAnim( name );
2939  }
2940 
2941  // find all animations with same name
2942  numAnims = 0;
2943  for( i = 0; i < anims.Num(); i++ ) {
2944  if ( !strcmp( anims[ i ]->Name(), name ) ) {
2945  animList[ numAnims++ ] = i;
2946  if ( numAnims >= MAX_ANIMS ) {
2947  break;
2948  }
2949  }
2950  }
2951 
2952  if ( !numAnims ) {
2953  return 0;
2954  }
2955 
2956  // get a random anim
2957  //FIXME: don't access gameLocal here?
2958  which = gameLocal.random.RandomInt( numAnims );
2959  return animList[ which ] + 1;
2960 }
2961 
2962 /*
2963 =====================
2964 idDeclModelDef::GetSkin
2965 =====================
2966 */
2967 const idDeclSkin *idDeclModelDef::GetSkin( void ) const {
2968  return skin;
2969 }
2970 
2971 /*
2972 =====================
2973 idDeclModelDef::GetModelName
2974 =====================
2975 */
2976 const char *idDeclModelDef::GetModelName( void ) const {
2977  if ( modelHandle ) {
2978  return modelHandle->Name();
2979  } else {
2980  return "";
2981  }
2982 }
2983 
2984 /*
2985 =====================
2986 idDeclModelDef::Joints
2987 =====================
2988 */
2990  return joints;
2991 }
2992 
2993 /*
2994 =====================
2995 idDeclModelDef::JointParents
2996 =====================
2997 */
2998 const int * idDeclModelDef::JointParents( void ) const {
2999  return jointParents.Ptr();
3000 }
3001 
3002 /*
3003 =====================
3004 idDeclModelDef::NumJoints
3005 =====================
3006 */
3007 int idDeclModelDef::NumJoints( void ) const {
3008  return joints.Num();
3009 }
3010 
3011 /*
3012 =====================
3013 idDeclModelDef::GetJoint
3014 =====================
3015 */
3016 const jointInfo_t *idDeclModelDef::GetJoint( int jointHandle ) const {
3017  if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) {
3018  gameLocal.Error( "idDeclModelDef::GetJoint : joint handle out of range" );
3019  }
3020  return &joints[ jointHandle ];
3021 }
3022 
3023 /*
3024 ====================
3025 idDeclModelDef::GetJointName
3026 ====================
3027 */
3028 const char *idDeclModelDef::GetJointName( int jointHandle ) const {
3029  const idMD5Joint *joint;
3030 
3031  if ( !modelHandle ) {
3032  return NULL;
3033  }
3034 
3035  if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) {
3036  gameLocal.Error( "idDeclModelDef::GetJointName : joint handle out of range" );
3037  }
3038 
3039  joint = modelHandle->GetJoints();
3040  return joint[ jointHandle ].name.c_str();
3041 }
3042 
3043 /*
3044 =====================
3045 idDeclModelDef::NumJointsOnChannel
3046 =====================
3047 */
3048 int idDeclModelDef::NumJointsOnChannel( int channel ) const {
3049  if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) {
3050  gameLocal.Error( "idDeclModelDef::NumJointsOnChannel : channel out of range" );
3051  }
3052  return channelJoints[ channel ].Num();
3053 }
3054 
3055 /*
3056 =====================
3057 idDeclModelDef::GetChannelJoints
3058 =====================
3059 */
3060 const int * idDeclModelDef::GetChannelJoints( int channel ) const {
3061  if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) {
3062  gameLocal.Error( "idDeclModelDef::GetChannelJoints : channel out of range" );
3063  }
3064  return channelJoints[ channel ].Ptr();
3065 }
3066 
3067 /*
3068 =====================
3069 idDeclModelDef::GetVisualOffset
3070 =====================
3071 */
3073  return offset;
3074 }
3075 
3076 /***********************************************************************
3077 
3078  idAnimator
3079 
3080 ***********************************************************************/
3081 
3082 /*
3083 =====================
3084 idAnimator::idAnimator
3085 =====================
3086 */
3088  int i, j;
3089 
3090  modelDef = NULL;
3091  entity = NULL;
3092  numJoints = 0;
3093  joints = NULL;
3094  lastTransformTime = -1;
3095  stoppedAnimatingUpdate = false;
3096  removeOriginOffset = false;
3097  forceUpdate = false;
3098 
3099  frameBounds.Clear();
3100 
3104 
3105  ClearAFPose();
3106 
3107  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3108  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3109  channels[ i ][ j ].Reset( NULL );
3110  }
3111  }
3112 }
3113 
3114 /*
3115 =====================
3116 idAnimator::~idAnimator
3117 =====================
3118 */
3120  FreeData();
3121 }
3122 
3123 /*
3124 =====================
3125 idAnimator::Allocated
3126 =====================
3127 */
3128 size_t idAnimator::Allocated( void ) const {
3129  size_t size;
3130 
3132 
3133  return size;
3134 }
3135 
3136 /*
3137 =====================
3138 idAnimator::Save
3139 
3140 archives object for save game file
3141 =====================
3142 */
3143 void idAnimator::Save( idSaveGame *savefile ) const {
3144  int i;
3145  int j;
3146 
3147  savefile->WriteModelDef( modelDef );
3148  savefile->WriteObject( entity );
3149 
3150  savefile->WriteInt( jointMods.Num() );
3151  for( i = 0; i < jointMods.Num(); i++ ) {
3152  savefile->WriteInt( jointMods[ i ]->jointnum );
3153  savefile->WriteMat3( jointMods[ i ]->mat );
3154  savefile->WriteVec3( jointMods[ i ]->pos );
3155  savefile->WriteInt( (int&)jointMods[ i ]->transform_pos );
3156  savefile->WriteInt( (int&)jointMods[ i ]->transform_axis );
3157  }
3158 
3159  savefile->WriteInt( numJoints );
3160  for ( i = 0; i < numJoints; i++ ) {
3161  float *data = joints[i].ToFloatPtr();
3162  for ( j = 0; j < 12; j++ ) {
3163  savefile->WriteFloat( data[j] );
3164  }
3165  }
3166 
3167  savefile->WriteInt( lastTransformTime );
3168  savefile->WriteBool( stoppedAnimatingUpdate );
3169  savefile->WriteBool( forceUpdate );
3170  savefile->WriteBounds( frameBounds );
3171 
3172  savefile->WriteFloat( AFPoseBlendWeight );
3173 
3174  savefile->WriteInt( AFPoseJoints.Num() );
3175  for ( i = 0; i < AFPoseJoints.Num(); i++ ) {
3176  savefile->WriteInt( AFPoseJoints[i] );
3177  }
3178 
3179  savefile->WriteInt( AFPoseJointMods.Num() );
3180  for ( i = 0; i < AFPoseJointMods.Num(); i++ ) {
3181  savefile->WriteInt( (int&)AFPoseJointMods[i].mod );
3182  savefile->WriteMat3( AFPoseJointMods[i].axis );
3183  savefile->WriteVec3( AFPoseJointMods[i].origin );
3184  }
3185 
3186  savefile->WriteInt( AFPoseJointFrame.Num() );
3187  for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) {
3188  savefile->WriteFloat( AFPoseJointFrame[i].q.x );
3189  savefile->WriteFloat( AFPoseJointFrame[i].q.y );
3190  savefile->WriteFloat( AFPoseJointFrame[i].q.z );
3191  savefile->WriteFloat( AFPoseJointFrame[i].q.w );
3192  savefile->WriteVec3( AFPoseJointFrame[i].t );
3193  }
3194 
3195  savefile->WriteBounds( AFPoseBounds );
3196  savefile->WriteInt( AFPoseTime );
3197 
3198  savefile->WriteBool( removeOriginOffset );
3199 
3200  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3201  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3202  channels[ i ][ j ].Save( savefile );
3203  }
3204  }
3205 }
3206 
3207 /*
3208 =====================
3209 idAnimator::Restore
3210 
3211 unarchives object from save game file
3212 =====================
3213 */
3215  int i;
3216  int j;
3217  int num;
3218 
3219  savefile->ReadModelDef( modelDef );
3220  savefile->ReadObject( reinterpret_cast<idClass *&>( entity ) );
3221 
3222  savefile->ReadInt( num );
3223  jointMods.SetNum( num );
3224  for( i = 0; i < num; i++ ) {
3225  jointMods[ i ] = new jointMod_t;
3226  savefile->ReadInt( (int&)jointMods[ i ]->jointnum );
3227  savefile->ReadMat3( jointMods[ i ]->mat );
3228  savefile->ReadVec3( jointMods[ i ]->pos );
3229  savefile->ReadInt( (int&)jointMods[ i ]->transform_pos );
3230  savefile->ReadInt( (int&)jointMods[ i ]->transform_axis );
3231  }
3232 
3233  savefile->ReadInt( numJoints );
3234  joints = (idJointMat *) Mem_Alloc16( numJoints * sizeof( joints[0] ) );
3235  for ( i = 0; i < numJoints; i++ ) {
3236  float *data = joints[i].ToFloatPtr();
3237  for ( j = 0; j < 12; j++ ) {
3238  savefile->ReadFloat( data[j] );
3239  }
3240  }
3241 
3242  savefile->ReadInt( lastTransformTime );
3243  savefile->ReadBool( stoppedAnimatingUpdate );
3244  savefile->ReadBool( forceUpdate );
3245  savefile->ReadBounds( frameBounds );
3246 
3247  savefile->ReadFloat( AFPoseBlendWeight );
3248 
3249  savefile->ReadInt( num );
3251  AFPoseJoints.SetNum( num );
3252  for ( i = 0; i < AFPoseJoints.Num(); i++ ) {
3253  savefile->ReadInt( AFPoseJoints[i] );
3254  }
3255 
3256  savefile->ReadInt( num );
3258  AFPoseJointMods.SetNum( num );
3259  for ( i = 0; i < AFPoseJointMods.Num(); i++ ) {
3260  savefile->ReadInt( (int&)AFPoseJointMods[i].mod );
3261  savefile->ReadMat3( AFPoseJointMods[i].axis );
3262  savefile->ReadVec3( AFPoseJointMods[i].origin );
3263  }
3264 
3265  savefile->ReadInt( num );
3267  AFPoseJointFrame.SetNum( num );
3268  for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) {
3269  savefile->ReadFloat( AFPoseJointFrame[i].q.x );
3270  savefile->ReadFloat( AFPoseJointFrame[i].q.y );
3271  savefile->ReadFloat( AFPoseJointFrame[i].q.z );
3272  savefile->ReadFloat( AFPoseJointFrame[i].q.w );
3273  savefile->ReadVec3( AFPoseJointFrame[i].t );
3274  }
3275 
3276  savefile->ReadBounds( AFPoseBounds );
3277  savefile->ReadInt( AFPoseTime );
3278 
3279  savefile->ReadBool( removeOriginOffset );
3280 
3281  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3282  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3283  channels[ i ][ j ].Restore( savefile, modelDef );
3284  }
3285  }
3286 }
3287 
3288 /*
3289 =====================
3290 idAnimator::FreeData
3291 =====================
3292 */
3293 void idAnimator::FreeData( void ) {
3294  int i, j;
3295 
3296  if ( entity ) {
3298  }
3299 
3300  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3301  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3302  channels[ i ][ j ].Reset( NULL );
3303  }
3304  }
3305 
3306  jointMods.DeleteContents( true );
3307 
3308  Mem_Free16( joints );
3309  joints = NULL;
3310  numJoints = 0;
3311 
3312  modelDef = NULL;
3313 
3314  ForceUpdate();
3315 }
3316 
3317 /*
3318 =====================
3319 idAnimator::PushAnims
3320 =====================
3321 */
3322 void idAnimator::PushAnims( int channelNum, int currentTime, int blendTime ) {
3323  int i;
3324  idAnimBlend *channel;
3325 
3326  channel = channels[ channelNum ];
3327  if ( !channel[ 0 ].GetWeight( currentTime ) || ( channel[ 0 ].starttime == currentTime ) ) {
3328  return;
3329  }
3330 
3331  for( i = ANIM_MaxAnimsPerChannel - 1; i > 0; i-- ) {
3332  channel[ i ] = channel[ i - 1 ];
3333  }
3334 
3335  channel[ 0 ].Reset( modelDef );
3336  channel[ 1 ].Clear( currentTime, blendTime );
3337  ForceUpdate();
3338 }
3339 
3340 /*
3341 =====================
3342 idAnimator::SetModel
3343 =====================
3344 */
3345 idRenderModel *idAnimator::SetModel( const char *modelname ) {
3346  int i, j;
3347 
3348  FreeData();
3349 
3350  // check if we're just clearing the model
3351  if ( !modelname || !*modelname ) {
3352  return NULL;
3353  }
3354 
3355  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
3356  if ( !modelDef ) {
3357  return NULL;
3358  }
3359 
3360  idRenderModel *renderModel = modelDef->ModelHandle();
3361  if ( !renderModel ) {
3362  modelDef = NULL;
3363  return NULL;
3364  }
3365 
3366  // make sure model hasn't been purged
3367  modelDef->Touch();
3368 
3370  modelDef->ModelHandle()->Reset();
3371 
3372  // set the modelDef on all channels
3373  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3374  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3375  channels[ i ][ j ].Reset( modelDef );
3376  }
3377  }
3378 
3379  return modelDef->ModelHandle();
3380 }
3381 
3382 /*
3383 =====================
3384 idAnimator::Size
3385 =====================
3386 */
3387 size_t idAnimator::Size( void ) const {
3388  return sizeof( *this ) + Allocated();
3389 }
3390 
3391 /*
3392 =====================
3393 idAnimator::SetEntity
3394 =====================
3395 */
3397  entity = ent;
3398 }
3399 
3400 /*
3401 =====================
3402 idAnimator::GetEntity
3403 =====================
3404 */
3406  return entity;
3407 }
3408 
3409 /*
3410 =====================
3411 idAnimator::RemoveOriginOffset
3412 =====================
3413 */
3414 void idAnimator::RemoveOriginOffset( bool remove ) {
3415  removeOriginOffset = remove;
3416 }
3417 
3418 /*
3419 =====================
3420 idAnimator::RemoveOrigin
3421 =====================
3422 */
3423 bool idAnimator::RemoveOrigin( void ) const {
3424  return removeOriginOffset;
3425 }
3426 
3427 /*
3428 =====================
3429 idAnimator::GetJointList
3430 =====================
3431 */
3432 void idAnimator::GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const {
3433  if ( modelDef ) {
3434  modelDef->GetJointList( jointnames, jointList );
3435  }
3436 }
3437 
3438 /*
3439 =====================
3440 idAnimator::NumAnims
3441 =====================
3442 */
3443 int idAnimator::NumAnims( void ) const {
3444  if ( !modelDef ) {
3445  return 0;
3446  }
3447 
3448  return modelDef->NumAnims();
3449 }
3450 
3451 /*
3452 =====================
3453 idAnimator::GetAnim
3454 =====================
3455 */
3456 const idAnim *idAnimator::GetAnim( int index ) const {
3457  if ( !modelDef ) {
3458  return NULL;
3459  }
3460 
3461  return modelDef->GetAnim( index );
3462 }
3463 
3464 /*
3465 =====================
3466 idAnimator::GetAnim
3467 =====================
3468 */
3469 int idAnimator::GetAnim( const char *name ) const {
3470  if ( !modelDef ) {
3471  return 0;
3472  }
3473 
3474  return modelDef->GetAnim( name );
3475 }
3476 
3477 /*
3478 =====================
3479 idAnimator::HasAnim
3480 =====================
3481 */
3482 bool idAnimator::HasAnim( const char *name ) const {
3483  if ( !modelDef ) {
3484  return false;
3485  }
3486 
3487  return modelDef->HasAnim( name );
3488 }
3489 
3490 /*
3491 =====================
3492 idAnimator::NumJoints
3493 =====================
3494 */
3495 int idAnimator::NumJoints( void ) const {
3496  return numJoints;
3497 }
3498 
3499 /*
3500 =====================
3501 idAnimator::ModelHandle
3502 =====================
3503 */
3505  if ( !modelDef ) {
3506  return NULL;
3507  }
3508 
3509  return modelDef->ModelHandle();
3510 }
3511 
3512 /*
3513 =====================
3514 idAnimator::ModelDef
3515 =====================
3516 */
3517 const idDeclModelDef *idAnimator::ModelDef( void ) const {
3518  return modelDef;
3519 }
3520 
3521 /*
3522 =====================
3523 idAnimator::CurrentAnim
3524 =====================
3525 */
3527  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3528  gameLocal.Error( "idAnimator::CurrentAnim : channel out of range" );
3529  }
3530 
3531  return &channels[ channelNum ][ 0 ];
3532 }
3533 
3534 /*
3535 =====================
3536 idAnimator::Clear
3537 =====================
3538 */
3539 void idAnimator::Clear( int channelNum, int currentTime, int cleartime ) {
3540  int i;
3541  idAnimBlend *blend;
3542 
3543  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3544  gameLocal.Error( "idAnimator::Clear : channel out of range" );
3545  }
3546 
3547  blend = channels[ channelNum ];
3548  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3549  blend->Clear( currentTime, cleartime );
3550  }
3551  ForceUpdate();
3552 }
3553 
3554 /*
3555 =====================
3556 idAnimator::SetFrame
3557 =====================
3558 */
3559 void idAnimator::SetFrame( int channelNum, int animNum, int frame, int currentTime, int blendTime ) {
3560  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3561  gameLocal.Error( "idAnimator::SetFrame : channel out of range" );
3562  }
3563 
3564  if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3565  return;
3566  }
3567 
3568  PushAnims( channelNum, currentTime, blendTime );
3569  channels[ channelNum ][ 0 ].SetFrame( modelDef, animNum, frame, currentTime, blendTime );
3570  if ( entity ) {
3572  }
3573 }
3574 
3575 /*
3576 =====================
3577 idAnimator::CycleAnim
3578 =====================
3579 */
3580 void idAnimator::CycleAnim( int channelNum, int animNum, int currentTime, int blendTime ) {
3581  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3582  gameLocal.Error( "idAnimator::CycleAnim : channel out of range" );
3583  }
3584 
3585  if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3586  return;
3587  }
3588 
3589  PushAnims( channelNum, currentTime, blendTime );
3590  channels[ channelNum ][ 0 ].CycleAnim( modelDef, animNum, currentTime, blendTime );
3591  if ( entity ) {
3593  }
3594 }
3595 
3596 /*
3597 =====================
3598 idAnimator::PlayAnim
3599 =====================
3600 */
3601 void idAnimator::PlayAnim( int channelNum, int animNum, int currentTime, int blendTime ) {
3602  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3603  gameLocal.Error( "idAnimator::PlayAnim : channel out of range" );
3604  }
3605 
3606  if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3607  return;
3608  }
3609 
3610  PushAnims( channelNum, currentTime, blendTime );
3611  channels[ channelNum ][ 0 ].PlayAnim( modelDef, animNum, currentTime, blendTime );
3612  if ( entity ) {
3614  }
3615 }
3616 
3617 /*
3618 =====================
3619 idAnimator::SyncAnimChannels
3620 =====================
3621 */
3622 void idAnimator::SyncAnimChannels( int channelNum, int fromChannelNum, int currentTime, int blendTime ) {
3623  if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) || ( fromChannelNum < 0 ) || ( fromChannelNum >= ANIM_NumAnimChannels ) ) {
3624  gameLocal.Error( "idAnimator::SyncToChannel : channel out of range" );
3625  }
3626 
3627  idAnimBlend &fromBlend = channels[ fromChannelNum ][ 0 ];
3628  idAnimBlend &toBlend = channels[ channelNum ][ 0 ];
3629 
3630  float weight = fromBlend.blendEndValue;
3631  if ( ( fromBlend.Anim() != toBlend.Anim() ) || ( fromBlend.GetStartTime() != toBlend.GetStartTime() ) || ( fromBlend.GetEndTime() != toBlend.GetEndTime() ) ) {
3632  PushAnims( channelNum, currentTime, blendTime );
3633  toBlend = fromBlend;
3634  toBlend.blendStartValue = 0.0f;
3635  toBlend.blendEndValue = 0.0f;
3636  }
3637  toBlend.SetWeight( weight, currentTime - 1, blendTime );
3638 
3639  // disable framecommands on the current channel so that commands aren't called twice
3640  toBlend.AllowFrameCommands( false );
3641 
3642  if ( entity ) {
3644  }
3645 }
3646 
3647 /*
3648 =====================
3649 idAnimator::SetJointPos
3650 =====================
3651 */
3652 void idAnimator::SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) {
3653  int i;
3654  jointMod_t *jointMod;
3655 
3656  if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3657  return;
3658  }
3659 
3660  jointMod = NULL;
3661  for( i = 0; i < jointMods.Num(); i++ ) {
3662  if ( jointMods[ i ]->jointnum == jointnum ) {
3663  jointMod = jointMods[ i ];
3664  break;
3665  } else if ( jointMods[ i ]->jointnum > jointnum ) {
3666  break;
3667  }
3668  }
3669 
3670  if ( !jointMod ) {
3671  jointMod = new jointMod_t;
3672  jointMod->jointnum = jointnum;
3673  jointMod->mat.Identity();
3674  jointMod->transform_axis = JOINTMOD_NONE;
3675  jointMods.Insert( jointMod, i );
3676  }
3677 
3678  jointMod->pos = pos;
3679  jointMod->transform_pos = transform_type;
3680 
3681  if ( entity ) {
3683  }
3684  ForceUpdate();
3685 }
3686 
3687 /*
3688 =====================
3689 idAnimator::SetJointAxis
3690 =====================
3691 */
3692 void idAnimator::SetJointAxis( jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat ) {
3693  int i;
3694  jointMod_t *jointMod;
3695 
3696  if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3697  return;
3698  }
3699 
3700  jointMod = NULL;
3701  for( i = 0; i < jointMods.Num(); i++ ) {
3702  if ( jointMods[ i ]->jointnum == jointnum ) {
3703  jointMod = jointMods[ i ];
3704  break;
3705  } else if ( jointMods[ i ]->jointnum > jointnum ) {
3706  break;
3707  }
3708  }
3709 
3710  if ( !jointMod ) {
3711  jointMod = new jointMod_t;
3712  jointMod->jointnum = jointnum;
3713  jointMod->pos.Zero();
3714  jointMod->transform_pos = JOINTMOD_NONE;
3715  jointMods.Insert( jointMod, i );
3716  }
3717 
3718  jointMod->mat = mat;
3719  jointMod->transform_axis = transform_type;
3720 
3721  if ( entity ) {
3723  }
3724  ForceUpdate();
3725 }
3726 
3727 /*
3728 =====================
3729 idAnimator::ClearJoint
3730 =====================
3731 */
3733  int i;
3734 
3735  if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3736  return;
3737  }
3738 
3739  for( i = 0; i < jointMods.Num(); i++ ) {
3740  if ( jointMods[ i ]->jointnum == jointnum ) {
3741  delete jointMods[ i ];
3742  jointMods.RemoveIndex( i );
3743  ForceUpdate();
3744  break;
3745  } else if ( jointMods[ i ]->jointnum > jointnum ) {
3746  break;
3747  }
3748  }
3749 }
3750 
3751 /*
3752 =====================
3753 idAnimator::ClearAllJoints
3754 =====================
3755 */
3757  if ( jointMods.Num() ) {
3758  ForceUpdate();
3759  }
3760  jointMods.DeleteContents( true );
3761 }
3762 
3763 /*
3764 =====================
3765 idAnimator::ClearAllAnims
3766 =====================
3767 */
3768 void idAnimator::ClearAllAnims( int currentTime, int cleartime ) {
3769  int i;
3770 
3771  for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
3772  Clear( i, currentTime, cleartime );
3773  }
3774 
3775  ClearAFPose();
3776  ForceUpdate();
3777 }
3778 
3779 /*
3780 ====================
3781 idAnimator::GetDelta
3782 ====================
3783 */
3784 void idAnimator::GetDelta( int fromtime, int totime, idVec3 &delta ) const {
3785  int i;
3786  const idAnimBlend *blend;
3787  float blendWeight;
3788 
3789  if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) {
3790  delta.Zero();
3791  return;
3792  }
3793 
3794  delta.Zero();
3795  blendWeight = 0.0f;
3796 
3797  blend = channels[ ANIMCHANNEL_ALL ];
3798  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3799  blend->BlendDelta( fromtime, totime, delta, blendWeight );
3800  }
3801 
3802  if ( modelDef->Joints()[ 0 ].channel ) {
3803  blend = channels[ modelDef->Joints()[ 0 ].channel ];
3804  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3805  blend->BlendDelta( fromtime, totime, delta, blendWeight );
3806  }
3807  }
3808 }
3809 
3810 /*
3811 ====================
3812 idAnimator::GetDeltaRotation
3813 ====================
3814 */
3815 bool idAnimator::GetDeltaRotation( int fromtime, int totime, idMat3 &delta ) const {
3816  int i;
3817  const idAnimBlend *blend;
3818  float blendWeight;
3819  idQuat q;
3820 
3821  if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) {
3822  delta.Identity();
3823  return false;
3824  }
3825 
3826  q.Set( 0.0f, 0.0f, 0.0f, 1.0f );
3827  blendWeight = 0.0f;
3828 
3829  blend = channels[ ANIMCHANNEL_ALL ];
3830  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3831  blend->BlendDeltaRotation( fromtime, totime, q, blendWeight );
3832  }
3833 
3834  if ( modelDef->Joints()[ 0 ].channel ) {
3835  blend = channels[ modelDef->Joints()[ 0 ].channel ];
3836  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3837  blend->BlendDeltaRotation( fromtime, totime, q, blendWeight );
3838  }
3839  }
3840 
3841  if ( blendWeight > 0.0f ) {
3842  delta = q.ToMat3();
3843  return true;
3844  } else {
3845  delta.Identity();
3846  return false;
3847  }
3848 }
3849 
3850 /*
3851 ====================
3852 idAnimator::GetOrigin
3853 ====================
3854 */
3855 void idAnimator::GetOrigin( int currentTime, idVec3 &pos ) const {
3856  int i;
3857  const idAnimBlend *blend;
3858  float blendWeight;
3859 
3860  if ( !modelDef || !modelDef->ModelHandle() ) {
3861  pos.Zero();
3862  return;
3863  }
3864 
3865  pos.Zero();
3866  blendWeight = 0.0f;
3867 
3868  blend = channels[ ANIMCHANNEL_ALL ];
3869  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3870  blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset );
3871  }
3872 
3873  if ( modelDef->Joints()[ 0 ].channel ) {
3874  blend = channels[ modelDef->Joints()[ 0 ].channel ];
3875  for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3876  blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset );
3877  }
3878  }
3879 
3880  pos += modelDef->GetVisualOffset();
3881 }
3882 
3883 /*
3884 ====================
3885 idAnimator::GetBounds
3886 ====================
3887 */
3888 bool idAnimator::GetBounds( int currentTime, idBounds &bounds ) {
3889  int i, j;
3890  const idAnimBlend *blend;
3891  int count;
3892 
3893  if ( !modelDef || !modelDef->ModelHandle() ) {
3894  return false;
3895  }
3896 
3897  if ( AFPoseJoints.Num() ) {
3898  bounds = AFPoseBounds;
3899  count = 1;
3900  } else {
3901  bounds.Clear();
3902  count = 0;
3903  }
3904 
3905  blend = channels[ 0 ];
3906  for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3907  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
3908  if ( blend->AddBounds( currentTime, bounds, removeOriginOffset ) ) {
3909  count++;
3910  }
3911  }
3912  }
3913 
3914  if ( !count ) {
3915  if ( !frameBounds.IsCleared() ) {
3916  bounds = frameBounds;
3917  return true;
3918  } else {
3919  bounds.Zero();
3920  return false;
3921  }
3922  }
3923 
3924  bounds.TranslateSelf( modelDef->GetVisualOffset() );
3925 
3926  if ( g_debugBounds.GetBool() ) {
3927  if ( bounds[1][0] - bounds[0][0] > 2048 || bounds[1][1] - bounds[0][1] > 2048 ) {
3928  if ( entity ) {
3929  gameLocal.Warning( "big frameBounds on entity '%s' with model '%s': %f,%f", entity->name.c_str(), modelDef->ModelHandle()->Name(), bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1] );
3930  } else {
3931  gameLocal.Warning( "big frameBounds on model '%s': %f,%f", modelDef->ModelHandle()->Name(), bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1] );
3932  }
3933  }
3934  }
3935 
3936  frameBounds = bounds;
3937 
3938  return true;
3939 }
3940 
3941 /*
3942 =====================
3943 idAnimator::InitAFPose
3944 =====================
3945 */
3947 
3948  if ( !modelDef ) {
3949  return;
3950  }
3951 
3952  AFPoseJoints.SetNum( modelDef->Joints().Num(), false );
3953  AFPoseJoints.SetNum( 0, false );
3954  AFPoseJointMods.SetNum( modelDef->Joints().Num(), false );
3955  AFPoseJointFrame.SetNum( modelDef->Joints().Num(), false );
3956 }
3957 
3958 /*
3959 =====================
3960 idAnimator::SetAFPoseJointMod
3961 =====================
3962 */
3963 void idAnimator::SetAFPoseJointMod( const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin ) {
3964  AFPoseJointMods[jointNum].mod = mod;
3965  AFPoseJointMods[jointNum].axis = axis;
3966  AFPoseJointMods[jointNum].origin = origin;
3967 
3968  int index = idBinSearch_GreaterEqual<int>( AFPoseJoints.Ptr(), AFPoseJoints.Num(), jointNum );
3969  if ( index >= AFPoseJoints.Num() || jointNum != AFPoseJoints[index] ) {
3970  AFPoseJoints.Insert( jointNum, index );
3971  }
3972 }
3973 
3974 /*
3975 =====================
3976 idAnimator::FinishAFPose
3977 =====================
3978 */
3979 void idAnimator::FinishAFPose( int animNum, const idBounds &bounds, const int time ) {
3980  int i, j;
3981  int numJoints;
3982  int parentNum;
3983  int jointMod;
3984  int jointNum;
3985  const int * jointParent;
3986 
3987  if ( !modelDef ) {
3988  return;
3989  }
3990 
3991  const idAnim *anim = modelDef->GetAnim( animNum );
3992  if ( !anim ) {
3993  return;
3994  }
3995 
3996  numJoints = modelDef->Joints().Num();
3997  if ( !numJoints ) {
3998  return;
3999  }
4000 
4002  const idMD5Anim *md5anim = anim->MD5Anim( 0 );
4003 
4004  if ( numJoints != md5anim->NumJoints() ) {
4005  gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", md5->Name(), md5anim->Name() );
4006  return;
4007  }
4008 
4009  idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
4011 
4012  if ( removeOriginOffset ) {
4013 #ifdef VELOCITY_MOVE
4014  jointFrame[ 0 ].t.x = 0.0f;
4015 #else
4016  jointFrame[ 0 ].t.Zero();
4017 #endif
4018  }
4019 
4020  idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( *joints ) );
4021 
4022  // convert the joint quaternions to joint matrices
4023  SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
4024 
4025  // first joint is always root of entire hierarchy
4026  if ( AFPoseJoints.Num() && AFPoseJoints[0] == 0 ) {
4027  switch( AFPoseJointMods[0].mod ) {
4028  case AF_JOINTMOD_AXIS: {
4029  joints[0].SetRotation( AFPoseJointMods[0].axis );
4030  break;
4031  }
4032  case AF_JOINTMOD_ORIGIN: {
4033  joints[0].SetTranslation( AFPoseJointMods[0].origin );
4034  break;
4035  }
4036  case AF_JOINTMOD_BOTH: {
4037  joints[0].SetRotation( AFPoseJointMods[0].axis );
4038  joints[0].SetTranslation( AFPoseJointMods[0].origin );
4039  break;
4040  }
4041  }
4042  j = 1;
4043  } else {
4044  j = 0;
4045  }
4046 
4047  // pointer to joint info
4048  jointParent = modelDef->JointParents();
4049 
4050  // transform the child joints
4051  for( i = 1; j < AFPoseJoints.Num(); j++, i++ ) {
4052  jointMod = AFPoseJoints[j];
4053 
4054  // transform any joints preceding the joint modifier
4055  SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod - 1 );
4056  i = jointMod;
4057 
4058  parentNum = jointParent[i];
4059 
4060  switch( AFPoseJointMods[jointMod].mod ) {
4061  case AF_JOINTMOD_AXIS: {
4062  joints[i].SetRotation( AFPoseJointMods[jointMod].axis );
4063  joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() );
4064  break;
4065  }
4066  case AF_JOINTMOD_ORIGIN: {
4067  joints[i].SetRotation( joints[i].ToMat3() * joints[parentNum].ToMat3() );
4068  joints[i].SetTranslation( AFPoseJointMods[jointMod].origin );
4069  break;
4070  }
4071  case AF_JOINTMOD_BOTH: {
4072  joints[i].SetRotation( AFPoseJointMods[jointMod].axis );
4073  joints[i].SetTranslation( AFPoseJointMods[jointMod].origin );
4074  break;
4075  }
4076  }
4077  }
4078 
4079  // transform the rest of the hierarchy
4080  SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 );
4081 
4082  // untransform hierarchy
4083  SIMDProcessor->UntransformJoints( joints, jointParent, 1, numJoints - 1 );
4084 
4085  // convert joint matrices back to joint quaternions
4087 
4088  // find all modified joints and their parents
4089  bool *blendJoints = (bool *) _alloca16( numJoints * sizeof( bool ) );
4090  memset( blendJoints, 0, numJoints * sizeof( bool ) );
4091 
4092  // mark all modified joints and their parents
4093  for( i = 0; i < AFPoseJoints.Num(); i++ ) {
4094  for( jointNum = AFPoseJoints[i]; jointNum != INVALID_JOINT; jointNum = jointParent[jointNum] ) {
4095  blendJoints[jointNum] = true;
4096  }
4097  }
4098 
4099  // lock all parents of modified joints
4100  AFPoseJoints.SetNum( 0, false );
4101  for ( i = 0; i < numJoints; i++ ) {
4102  if ( blendJoints[i] ) {
4103  AFPoseJoints.Append( i );
4104  }
4105  }
4106 
4107  AFPoseBounds = bounds;
4108  AFPoseTime = time;
4109 
4110  ForceUpdate();
4111 }
4112 
4113 /*
4114 =====================
4115 idAnimator::SetAFPoseBlendWeight
4116 =====================
4117 */
4118 void idAnimator::SetAFPoseBlendWeight( float blendWeight ) {
4119  AFPoseBlendWeight = blendWeight;
4120 }
4121 
4122 /*
4123 =====================
4124 idAnimator::BlendAFPose
4125 =====================
4126 */
4127 bool idAnimator::BlendAFPose( idJointQuat *blendFrame ) const {
4128 
4129  if ( !AFPoseJoints.Num() ) {
4130  return false;
4131  }
4132 
4134 
4135  return true;
4136 }
4137 
4138 /*
4139 =====================
4140 idAnimator::ClearAFPose
4141 =====================
4142 */
4144  if ( AFPoseJoints.Num() ) {
4145  ForceUpdate();
4146  }
4147  AFPoseBlendWeight = 1.0f;
4148  AFPoseJoints.SetNum( 0, false );
4149  AFPoseBounds.Clear();
4150  AFPoseTime = 0;
4151 }
4152 
4153 /*
4154 =====================
4155 idAnimator::ServiceAnims
4156 =====================
4157 */
4158 void idAnimator::ServiceAnims( int fromtime, int totime ) {
4159  int i, j;
4160  idAnimBlend *blend;
4161 
4162  if ( !modelDef ) {
4163  return;
4164  }
4165 
4166  if ( modelDef->ModelHandle() ) {
4167  blend = channels[ 0 ];
4168  for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4169  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4170  blend->CallFrameCommands( entity, fromtime, totime );
4171  }
4172  }
4173  }
4174 
4175  if ( !IsAnimating( totime ) ) {
4176  stoppedAnimatingUpdate = true;
4177  if ( entity ) {
4179 
4180  // present one more time with stopped animations so the renderer can properly recreate interactions
4182  }
4183  }
4184 }
4185 
4186 /*
4187 =====================
4188 idAnimator::IsAnimating
4189 =====================
4190 */
4191 bool idAnimator::IsAnimating( int currentTime ) const {
4192  int i, j;
4193  const idAnimBlend *blend;
4194 
4195  if ( !modelDef || !modelDef->ModelHandle() ) {
4196  return false;
4197  }
4198 
4199  // if animating with an articulated figure
4200  if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) {
4201  return true;
4202  }
4203 
4204  blend = channels[ 0 ];
4205  for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4206  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4207  if ( !blend->IsDone( currentTime ) ) {
4208  return true;
4209  }
4210  }
4211  }
4212 
4213  return false;
4214 }
4215 
4216 /*
4217 =====================
4218 idAnimator::FrameHasChanged
4219 =====================
4220 */
4221 bool idAnimator::FrameHasChanged( int currentTime ) const {
4222  int i, j;
4223  const idAnimBlend *blend;
4224 
4225  if ( !modelDef || !modelDef->ModelHandle() ) {
4226  return false;
4227  }
4228 
4229  // if animating with an articulated figure
4230  if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) {
4231  return true;
4232  }
4233 
4234  blend = channels[ 0 ];
4235  for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4236  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4237  if ( blend->FrameHasChanged( currentTime ) ) {
4238  return true;
4239  }
4240  }
4241  }
4242 
4243  if ( forceUpdate && IsAnimating( currentTime ) ) {
4244  return true;
4245  }
4246 
4247  return false;
4248 }
4249 
4250 /*
4251 =====================
4252 idAnimator::CreateFrame
4253 =====================
4254 */
4255 bool idAnimator::CreateFrame( int currentTime, bool force ) {
4256  int i, j;
4257  int numJoints;
4258  int parentNum;
4259  bool hasAnim;
4260  bool debugInfo;
4261  float baseBlend;
4262  float blendWeight;
4263  const idAnimBlend * blend;
4264  const int * jointParent;
4265  const jointMod_t * jointMod;
4266  const idJointQuat * defaultPose;
4267 
4268  static idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
4269 
4271  return false;
4272  }
4273 
4274  if ( !modelDef || !modelDef->ModelHandle() ) {
4275  return false;
4276  }
4277 
4278  if ( !force && !r_showSkel.GetInteger() ) {
4279  if ( lastTransformTime == currentTime ) {
4280  return false;
4281  }
4282  if ( lastTransformTime != -1 && !stoppedAnimatingUpdate && !IsAnimating( currentTime ) ) {
4283  return false;
4284  }
4285  }
4286 
4287  lastTransformTime = currentTime;
4288  stoppedAnimatingUpdate = false;
4289 
4290  if ( entity && ( ( g_debugAnim.GetInteger() == entity->entityNumber ) || ( g_debugAnim.GetInteger() == -2 ) ) ) {
4291  debugInfo = true;
4292  gameLocal.Printf( "---------------\n%d: entity '%s':\n", gameLocal.time, entity->GetName() );
4293  gameLocal.Printf( "model '%s':\n", modelDef->GetModelName() );
4294  } else {
4295  debugInfo = false;
4296  }
4297 
4298  // init the joint buffer
4299  if ( AFPoseJoints.Num() ) {
4300  // initialize with AF pose anim for the case where there are no other animations and no AF pose joint modifications
4301  defaultPose = AFPoseJointFrame.Ptr();
4302  } else {
4303  defaultPose = modelDef->GetDefaultPose();
4304  }
4305 
4306  if ( !defaultPose ) {
4307  //gameLocal.Warning( "idAnimator::CreateFrame: no defaultPose on '%s'", modelDef->Name() );
4308  return false;
4309  }
4310 
4311  numJoints = modelDef->Joints().Num();
4312  idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( jointFrame[0] ) );
4313  SIMDProcessor->Memcpy( jointFrame, defaultPose, numJoints * sizeof( jointFrame[0] ) );
4314 
4315  hasAnim = false;
4316 
4317  // blend the all channel
4318  baseBlend = 0.0f;
4319  blend = channels[ ANIMCHANNEL_ALL ];
4320  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4321  if ( blend->BlendAnim( currentTime, ANIMCHANNEL_ALL, numJoints, jointFrame, baseBlend, removeOriginOffset, false, debugInfo ) ) {
4322  hasAnim = true;
4323  if ( baseBlend >= 1.0f ) {
4324  break;
4325  }
4326  }
4327  }
4328 
4329  // only blend other channels if there's enough space to blend into
4330  if ( baseBlend < 1.0f ) {
4331  for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) {
4332  if ( !modelDef->NumJointsOnChannel( i ) ) {
4333  continue;
4334  }
4335  if ( i == ANIMCHANNEL_EYELIDS ) {
4336  // eyelids blend over any previous anims, so skip it and blend it later
4337  continue;
4338  }
4339  blendWeight = baseBlend;
4340  blend = channels[ i ];
4341  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4342  if ( blend->BlendAnim( currentTime, i, numJoints, jointFrame, blendWeight, removeOriginOffset, false, debugInfo ) ) {
4343  hasAnim = true;
4344  if ( blendWeight >= 1.0f ) {
4345  // fully blended
4346  break;
4347  }
4348  }
4349  }
4350 
4351  if ( debugInfo && !AFPoseJoints.Num() && !blendWeight ) {
4352  gameLocal.Printf( "%d: %s using default pose in model '%s'\n", gameLocal.time, channelNames[ i ], modelDef->GetModelName() );
4353  }
4354  }
4355  }
4356 
4357  // blend in the eyelids
4359  blend = channels[ ANIMCHANNEL_EYELIDS ];
4360  blendWeight = baseBlend;
4361  for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4362  if ( blend->BlendAnim( currentTime, ANIMCHANNEL_EYELIDS, numJoints, jointFrame, blendWeight, removeOriginOffset, true, debugInfo ) ) {
4363  hasAnim = true;
4364  if ( blendWeight >= 1.0f ) {
4365  // fully blended
4366  break;
4367  }
4368  }
4369  }
4370  }
4371 
4372  // blend the articulated figure pose
4373  if ( BlendAFPose( jointFrame ) ) {
4374  hasAnim = true;
4375  }
4376 
4377  if ( !hasAnim && !jointMods.Num() ) {
4378  // no animations were updated
4379  return false;
4380  }
4381 
4382  // convert the joint quaternions to rotation matrices
4383  SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
4384 
4385  // check if we need to modify the origin
4386  if ( jointMods.Num() && ( jointMods[0]->jointnum == 0 ) ) {
4387  jointMod = jointMods[0];
4388 
4389  switch( jointMod->transform_axis ) {
4390  case JOINTMOD_NONE:
4391  break;
4392 
4393  case JOINTMOD_LOCAL:
4394  joints[0].SetRotation( jointMod->mat * joints[0].ToMat3() );
4395  break;
4396 
4397  case JOINTMOD_WORLD:
4398  joints[0].SetRotation( joints[0].ToMat3() * jointMod->mat );
4399  break;
4400 
4403  joints[0].SetRotation( jointMod->mat );
4404  break;
4405  }
4406 
4407  switch( jointMod->transform_pos ) {
4408  case JOINTMOD_NONE:
4409  break;
4410 
4411  case JOINTMOD_LOCAL:
4412  joints[0].SetTranslation( joints[0].ToVec3() + jointMod->pos );
4413  break;
4414 
4416  case JOINTMOD_WORLD:
4418  joints[0].SetTranslation( jointMod->pos );
4419  break;
4420  }
4421  j = 1;
4422  } else {
4423  j = 0;
4424  }
4425 
4426  // add in the model offset
4427  joints[0].SetTranslation( joints[0].ToVec3() + modelDef->GetVisualOffset() );
4428 
4429  // pointer to joint info
4430  jointParent = modelDef->JointParents();
4431 
4432  // add in any joint modifications
4433  for( i = 1; j < jointMods.Num(); j++, i++ ) {
4434  jointMod = jointMods[j];
4435 
4436  // transform any joints preceding the joint modifier
4437  SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod->jointnum - 1 );
4438  i = jointMod->jointnum;
4439 
4440  parentNum = jointParent[i];
4441 
4442  // modify the axis
4443  switch( jointMod->transform_axis ) {
4444  case JOINTMOD_NONE:
4445  joints[i].SetRotation( joints[i].ToMat3() * joints[ parentNum ].ToMat3() );
4446  break;
4447 
4448  case JOINTMOD_LOCAL:
4449  joints[i].SetRotation( jointMod->mat * ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) );
4450  break;
4451 
4453  joints[i].SetRotation( jointMod->mat * joints[parentNum].ToMat3() );
4454  break;
4455 
4456  case JOINTMOD_WORLD:
4457  joints[i].SetRotation( ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) * jointMod->mat );
4458  break;
4459 
4461  joints[i].SetRotation( jointMod->mat );
4462  break;
4463  }
4464 
4465  // modify the position
4466  switch( jointMod->transform_pos ) {
4467  case JOINTMOD_NONE:
4468  joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() );
4469  break;
4470 
4471  case JOINTMOD_LOCAL:
4472  joints[i].SetTranslation( joints[parentNum].ToVec3() + ( joints[i].ToVec3() + jointMod->pos ) * joints[parentNum].ToMat3() );
4473  break;
4474 
4476  joints[i].SetTranslation( joints[parentNum].ToVec3() + jointMod->pos * joints[parentNum].ToMat3() );
4477  break;
4478 
4479  case JOINTMOD_WORLD:
4480  joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() + jointMod->pos );
4481  break;
4482 
4484  joints[i].SetTranslation( jointMod->pos );
4485  break;
4486  }
4487  }
4488 
4489  // transform the rest of the hierarchy
4490  SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 );
4491 
4492  return true;
4493 }
4494 
4495 /*
4496 =====================
4497 idAnimator::ForceUpdate
4498 =====================
4499 */
4501  lastTransformTime = -1;
4502  forceUpdate = true;
4503 }
4504 
4505 /*
4506 =====================
4507 idAnimator::ClearForceUpdate
4508 =====================
4509 */
4511  forceUpdate = false;
4512 }
4513 
4514 /*
4515 =====================
4516 idAnimator::GetJointTransform> gamex86.dll!idAnimator::ForceUpdate() Line 4268 C++
4517 
4518 =====================
4519 */
4520 bool idAnimator::GetJointTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
4521  if ( !modelDef || ( jointHandle < 0 ) || ( jointHandle >= modelDef->NumJoints() ) ) {
4522  return false;
4523  }
4524 
4525  CreateFrame( currentTime, false );
4526 
4527  offset = joints[ jointHandle ].ToVec3();
4528  axis = joints[ jointHandle ].ToMat3();
4529 
4530  return true;
4531 }
4532 
4533 /*
4534 =====================
4535 idAnimator::GetJointLocalTransform
4536 =====================
4537 */
4538 bool idAnimator::GetJointLocalTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
4539  if ( !modelDef ) {
4540  return false;
4541  }
4542 
4543  const idList<jointInfo_t> &modelJoints = modelDef->Joints();
4544 
4545  if ( ( jointHandle < 0 ) || ( jointHandle >= modelJoints.Num() ) ) {
4546  return false;
4547  }
4548 
4549  // FIXME: overkill
4550  CreateFrame( currentTime, false );
4551 
4552  if ( jointHandle > 0 ) {
4553  idJointMat m = joints[ jointHandle ];
4554  m /= joints[ modelJoints[ jointHandle ].parentNum ];
4555  offset = m.ToVec3();
4556  axis = m.ToMat3();
4557  } else {
4558  offset = joints[ jointHandle ].ToVec3();
4559  axis = joints[ jointHandle ].ToMat3();
4560  }
4561 
4562  return true;
4563 }
4564 
4565 /*
4566 =====================
4567 idAnimator::GetJointHandle
4568 =====================
4569 */
4571  if ( !modelDef || !modelDef->ModelHandle() ) {
4572  return INVALID_JOINT;
4573  }
4574 
4575  return modelDef->ModelHandle()->GetJointHandle( name );
4576 }
4577 
4578 /*
4579 =====================
4580 idAnimator::GetJointName
4581 =====================
4582 */
4583 const char *idAnimator::GetJointName( jointHandle_t handle ) const {
4584  if ( !modelDef || !modelDef->ModelHandle() ) {
4585  return "";
4586  }
4587 
4588  return modelDef->ModelHandle()->GetJointName( handle );
4589 }
4590 
4591 /*
4592 =====================
4593 idAnimator::GetChannelForJoint
4594 =====================
4595 */
4597  if ( !modelDef ) {
4598  gameLocal.Error( "idAnimator::GetChannelForJoint: NULL model" );
4599  }
4600 
4601  if ( ( joint < 0 ) || ( joint >= numJoints ) ) {
4602  gameLocal.Error( "idAnimator::GetChannelForJoint: invalid joint num (%d)", joint );
4603  }
4604 
4605  return modelDef->GetJoint( joint )->channel;
4606 }
4607 
4608 /*
4609 =====================
4610 idAnimator::GetFirstChild
4611 =====================
4612 */
4614  return GetFirstChild( GetJointHandle( name ) );
4615 }
4616 
4617 /*
4618 =====================
4619 idAnimator::GetFirstChild
4620 =====================
4621 */
4623  int i;
4624  int num;
4625  const jointInfo_t *joint;
4626 
4627  if ( !modelDef ) {
4628  return INVALID_JOINT;
4629  }
4630 
4631  num = modelDef->NumJoints();
4632  if ( !num ) {
4633  return jointnum;
4634  }
4635  joint = modelDef->GetJoint( 0 );
4636  for( i = 0; i < num; i++, joint++ ) {
4637  if ( joint->parentNum == jointnum ) {
4638  return ( jointHandle_t )joint->num;
4639  }
4640  }
4641  return jointnum;
4642 }
4643 
4644 /*
4645 =====================
4646 idAnimator::GetJoints
4647 =====================
4648 */
4649 void idAnimator::GetJoints( int *numJoints, idJointMat **jointsPtr ) {
4650  *numJoints = this->numJoints;
4651  *jointsPtr = this->joints;
4652 }
4653 
4654 /*
4655 =====================
4656 idAnimator::GetAnimFlags
4657 =====================
4658 */
4659 const animFlags_t idAnimator::GetAnimFlags( int animNum ) const {
4661 
4662  const idAnim *anim = GetAnim( animNum );
4663  if ( anim ) {
4664  return anim->GetAnimFlags();
4665  }
4666 
4667  memset( &result, 0, sizeof( result ) );
4668  return result;
4669 }
4670 
4671 /*
4672 =====================
4673 idAnimator::NumFrames
4674 =====================
4675 */
4676 int idAnimator::NumFrames( int animNum ) const {
4677  const idAnim *anim = GetAnim( animNum );
4678  if ( anim ) {
4679  return anim->NumFrames();
4680  } else {
4681  return 0;
4682  }
4683 }
4684 
4685 /*
4686 =====================
4687 idAnimator::NumSyncedAnims
4688 =====================
4689 */
4690 int idAnimator::NumSyncedAnims( int animNum ) const {
4691  const idAnim *anim = GetAnim( animNum );
4692  if ( anim ) {
4693  return anim->NumAnims();
4694  } else {
4695  return 0;
4696  }
4697 }
4698 
4699 /*
4700 =====================
4701 idAnimator::AnimName
4702 =====================
4703 */
4704 const char *idAnimator::AnimName( int animNum ) const {
4705  const idAnim *anim = GetAnim( animNum );
4706  if ( anim ) {
4707  return anim->Name();
4708  } else {
4709  return "";
4710  }
4711 }
4712 
4713 /*
4714 =====================
4715 idAnimator::AnimFullName
4716 =====================
4717 */
4718 const char *idAnimator::AnimFullName( int animNum ) const {
4719  const idAnim *anim = GetAnim( animNum );
4720  if ( anim ) {
4721  return anim->FullName();
4722  } else {
4723  return "";
4724  }
4725 }
4726 
4727 /*
4728 =====================
4729 idAnimator::AnimLength
4730 =====================
4731 */
4732 int idAnimator::AnimLength( int animNum ) const {
4733  const idAnim *anim = GetAnim( animNum );
4734  if ( anim ) {
4735  return anim->Length();
4736  } else {
4737  return 0;
4738  }
4739 }
4740 
4741 /*
4742 =====================
4743 idAnimator::TotalMovementDelta
4744 =====================
4745 */
4746 const idVec3 &idAnimator::TotalMovementDelta( int animNum ) const {
4747  const idAnim *anim = GetAnim( animNum );
4748  if ( anim ) {
4749  return anim->TotalMovementDelta();
4750  } else {
4751  return vec3_origin;
4752  }
4753 }
4754 
4755 /***********************************************************************
4756 
4757  Util functions
4758 
4759 ***********************************************************************/
4760 
4761 /*
4762 =====================
4763 ANIM_GetModelDefFromEntityDef
4764 =====================
4765 */
4767  const idDeclModelDef *modelDef;
4768 
4769  idStr name = args->GetString( "model" );
4770  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name, false ) );
4771  if ( modelDef && modelDef->ModelHandle() ) {
4772  return modelDef;
4773  }
4774 
4775  return NULL;
4776 }
4777 
4778 /*
4779 =====================
4780 idGameEdit::ANIM_GetModelFromEntityDef
4781 =====================
4782 */
4784  idRenderModel *model;
4785  const idDeclModelDef *modelDef;
4786 
4787  model = NULL;
4788 
4789  idStr name = args->GetString( "model" );
4790  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name, false ) );
4791  if ( modelDef ) {
4792  model = modelDef->ModelHandle();
4793  }
4794 
4795  if ( !model ) {
4796  model = renderModelManager->FindModel( name );
4797  }
4798 
4799  if ( model && model->IsDefaultModel() ) {
4800  return NULL;
4801  }
4802 
4803  return model;
4804 }
4805 
4806 /*
4807 =====================
4808 idGameEdit::ANIM_GetModelFromEntityDef
4809 =====================
4810 */
4812  const idDict *args;
4813 
4814  args = gameLocal.FindEntityDefDict( classname, false );
4815  if ( !args ) {
4816  return NULL;
4817  }
4818 
4819  return ANIM_GetModelFromEntityDef( args );
4820 }
4821 
4822 /*
4823 =====================
4824 idGameEdit::ANIM_GetModelOffsetFromEntityDef
4825 =====================
4826 */
4827 const idVec3 &idGameEdit::ANIM_GetModelOffsetFromEntityDef( const char *classname ) {
4828  const idDict *args;
4829  const idDeclModelDef *modelDef;
4830 
4831  args = gameLocal.FindEntityDefDict( classname, false );
4832  if ( !args ) {
4833  return vec3_origin;
4834  }
4835 
4836  modelDef = ANIM_GetModelDefFromEntityDef( args );
4837  if ( !modelDef ) {
4838  return vec3_origin;
4839  }
4840 
4841  return modelDef->GetVisualOffset();
4842 }
4843 
4844 /*
4845 =====================
4846 idGameEdit::ANIM_GetModelFromName
4847 =====================
4848 */
4850  const idDeclModelDef *modelDef;
4851  idRenderModel *model;
4852 
4853  model = NULL;
4854  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
4855  if ( modelDef ) {
4856  model = modelDef->ModelHandle();
4857  }
4858  if ( !model ) {
4859  model = renderModelManager->FindModel( modelName );
4860  }
4861  return model;
4862 }
4863 
4864 /*
4865 =====================
4866 idGameEdit::ANIM_GetAnimFromEntityDef
4867 =====================
4868 */
4869 const idMD5Anim *idGameEdit::ANIM_GetAnimFromEntityDef( const char *classname, const char *animname ) {
4870  const idDict *args;
4871  const idMD5Anim *md5anim;
4872  const idAnim *anim;
4873  int animNum;
4874  const char *modelname;
4875  const idDeclModelDef *modelDef;
4876 
4877  args = gameLocal.FindEntityDefDict( classname, false );
4878  if ( !args ) {
4879  return NULL;
4880  }
4881 
4882  md5anim = NULL;
4883  modelname = args->GetString( "model" );
4884  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4885  if ( modelDef ) {
4886  animNum = modelDef->GetAnim( animname );
4887  if ( animNum ) {
4888  anim = modelDef->GetAnim( animNum );
4889  if ( anim ) {
4890  md5anim = anim->MD5Anim( 0 );
4891  }
4892  }
4893  }
4894  return md5anim;
4895 }
4896 
4897 /*
4898 =====================
4899 idGameEdit::ANIM_GetNumAnimsFromEntityDef
4900 =====================
4901 */
4903  const char *modelname;
4904  const idDeclModelDef *modelDef;
4905 
4906  modelname = args->GetString( "model" );
4907  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4908  if ( modelDef ) {
4909  return modelDef->NumAnims();
4910  }
4911  return 0;
4912 }
4913 
4914 /*
4915 =====================
4916 idGameEdit::ANIM_GetAnimNameFromEntityDef
4917 =====================
4918 */
4919 const char *idGameEdit::ANIM_GetAnimNameFromEntityDef( const idDict *args, int animNum ) {
4920  const char *modelname;
4921  const idDeclModelDef *modelDef;
4922 
4923  modelname = args->GetString( "model" );
4924  modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4925  if ( modelDef ) {
4926  const idAnim* anim = modelDef->GetAnim( animNum );
4927  if ( anim ) {
4928  return anim->FullName();
4929  }
4930  }
4931  return "";
4932 }
4933 
4934 /*
4935 =====================
4936 idGameEdit::ANIM_GetAnim
4937 =====================
4938 */
4939 const idMD5Anim *idGameEdit::ANIM_GetAnim( const char *fileName ) {
4940  return animationLib.GetAnim( fileName );
4941 }
4942 
4943 /*
4944 =====================
4945 idGameEdit::ANIM_GetLength
4946 =====================
4947 */
4949  if ( !anim ) {
4950  return 0;
4951  }
4952  return anim->Length();
4953 }
4954 
4955 /*
4956 =====================
4957 idGameEdit::ANIM_GetNumFrames
4958 =====================
4959 */
4961  if ( !anim ) {
4962  return 0;
4963  }
4964  return anim->NumFrames();
4965 }
4966 
4967 /*
4968 =====================
4969 idGameEdit::ANIM_CreateAnimFrame
4970 =====================
4971 */
4972 void idGameEdit::ANIM_CreateAnimFrame( const idRenderModel *model, const idMD5Anim *anim, int numJoints, idJointMat *joints, int time, const idVec3 &offset, bool remove_origin_offset ) {
4973  int i;
4974  frameBlend_t frame;
4975  const idMD5Joint *md5joints;
4976  int *index;
4977 
4978  if ( !model || model->IsDefaultModel() || !anim ) {
4979  return;
4980  }
4981 
4982  if ( numJoints != model->NumJoints() ) {
4983  gameLocal.Error( "ANIM_CreateAnimFrame: different # of joints in renderEntity_t than in model (%s)", model->Name() );
4984  }
4985 
4986  if ( !model->NumJoints() ) {
4987  // FIXME: Print out a warning?
4988  return;
4989  }
4990 
4991  if ( !joints ) {
4992  gameLocal.Error( "ANIM_CreateAnimFrame: NULL joint frame pointer on model (%s)", model->Name() );
4993  }
4994 
4995  if ( numJoints != anim->NumJoints() ) {
4996  gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", model->Name(), anim->Name() );
4997  for( i = 0; i < numJoints; i++ ) {
4998  joints[i].SetRotation( mat3_identity );
4999  joints[i].SetTranslation( offset );
5000  }
5001  return;
5002  }
5003 
5004  // create index for all joints
5005  index = ( int * )_alloca16( numJoints * sizeof( int ) );
5006  for ( i = 0; i < numJoints; i++ ) {
5007  index[i] = i;
5008  }
5009 
5010  // create the frame
5011  anim->ConvertTimeToFrame( time, 1, frame );
5012  idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
5013  anim->GetInterpolatedFrame( frame, jointFrame, index, numJoints );
5014 
5015  // convert joint quaternions to joint matrices
5016  SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
5017 
5018  // first joint is always root of entire hierarchy
5019  if ( remove_origin_offset ) {
5020  joints[0].SetTranslation( offset );
5021  } else {
5022  joints[0].SetTranslation( joints[0].ToVec3() + offset );
5023  }
5024 
5025  // transform the children
5026  md5joints = model->GetJoints();
5027  for( i = 1; i < numJoints; i++ ) {
5028  joints[i] *= joints[ md5joints[i].parent - md5joints ];
5029  }
5030 }
5031 
5032 /*
5033 =====================
5034 idGameEdit::ANIM_CreateMeshForAnim
5035 =====================
5036 */
5037 idRenderModel *idGameEdit::ANIM_CreateMeshForAnim( idRenderModel *model, const char *classname, const char *animname, int frame, bool remove_origin_offset ) {
5038  renderEntity_t ent;
5039  const idDict *args;
5040  const char *temp;
5041  idRenderModel *newmodel;
5042  const idMD5Anim *md5anim;
5043  idStr filename;
5044  idStr extension;
5045  const idAnim *anim;
5046  int animNum;
5047  idVec3 offset;
5048  const idDeclModelDef *modelDef;
5049 
5050  if ( !model || model->IsDefaultModel() ) {
5051  return NULL;
5052  }
5053 
5054  args = gameLocal.FindEntityDefDict( classname, false );
5055  if ( !args ) {
5056  return NULL;
5057  }
5058 
5059  memset( &ent, 0, sizeof( ent ) );
5060 
5061  ent.bounds.Clear();
5062  ent.suppressSurfaceInViewID = 0;
5063 
5064  modelDef = ANIM_GetModelDefFromEntityDef( args );
5065  if ( modelDef ) {
5066  animNum = modelDef->GetAnim( animname );
5067  if ( !animNum ) {
5068  return NULL;
5069  }
5070  anim = modelDef->GetAnim( animNum );
5071  if ( !anim ) {
5072  return NULL;
5073  }
5074  md5anim = anim->MD5Anim( 0 );
5075  ent.customSkin = modelDef->GetDefaultSkin();
5076  offset = modelDef->GetVisualOffset();
5077  } else {
5078  filename = animname;
5079  filename.ExtractFileExtension( extension );
5080  if ( !extension.Length() ) {
5081  animname = args->GetString( va( "anim %s", animname ) );
5082  }
5083 
5084  md5anim = animationLib.GetAnim( animname );
5085  offset.Zero();
5086  }
5087 
5088  if ( !md5anim ) {
5089  return NULL;
5090  }
5091 
5092  temp = args->GetString( "skin", "" );
5093  if ( temp[ 0 ] ) {
5094  ent.customSkin = declManager->FindSkin( temp );
5095  }
5096 
5097  ent.numJoints = model->NumJoints();
5098  ent.joints = ( idJointMat * )Mem_Alloc16( ent.numJoints * sizeof( *ent.joints ) );
5099 
5100  ANIM_CreateAnimFrame( model, md5anim, ent.numJoints, ent.joints, FRAME2MS( frame ), offset, remove_origin_offset );
5101 
5102  newmodel = model->InstantiateDynamicModel( &ent, NULL, NULL );
5103 
5104  Mem_Free16( ent.joints );
5105  ent.joints = NULL;
5106 
5107  return newmodel;
5108 }
int GetLineNum(void) const
Definition: DeclManager.h:168
GLdouble GLdouble GLdouble GLdouble q
Definition: glext.h:2959
jointHandle_t
Definition: Model.h:156
const idEventDef AI_DisableEyeFocus("disableEyeFocus")
int CheckTokenString(const char *string)
Definition: Lexer.cpp:1007
Definition: Anim.h:111
const idEventDef AI_DirectDamage
int NumJoints(void) const
idBounds & TranslateSelf(const idVec3 &translation)
Definition: Bounds.h:336
#define strcmp
Definition: Str.h:41
bool ParseAnim(idLexer &src, int numDefaultAnims)
int GetChannelForJoint(jointHandle_t joint) const
virtual void VPCALL ConvertJointQuatsToJointMats(idJointMat *jointMats, const idJointQuat *jointQuats, const int numJoints)=0
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
bool GetJointTransform(jointHandle_t jointHandle, int currenttime, idVec3 &offset, idMat3 &axis)
int type
Definition: Token.h:77
int timeOffset
Definition: Anim.h:389
bool GetBounds(int currentTime, idBounds &bounds)
void SetCycleCount(int count)
virtual idRenderModel * InstantiateDynamicModel(const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel)=0
void Save(idSaveGame *savefile) const
float blendEndValue
Definition: Anim.h:395
assert(prefInfo.fullscreenBtn)
virtual const idSoundShader * FindSound(const char *name, bool makeDefault=true)=0
const idDict * FindEntityDefDict(const char *name, bool makeDefault=true) const
void SyncAnimChannels(int channelNum, int fromChannelNum, int currenttime, int blendTime)
bool IsAnimating(int currentTime) const
jointHandle_t GetFirstChild(jointHandle_t jointnum) const
void FinishAFPose(int animnum, const idBounds &bounds, const int time)
idMat3 mat3_identity(idVec3(1, 0, 0), idVec3(0, 1, 0), idVec3(0, 0, 1))
void SetAnimFlags(const animFlags_t &animflags)
int channel
Definition: Anim.h:78
void WriteObject(const idClass *obj)
Definition: SaveGame.cpp:329
const idEventDef AI_BeginAttack
int Length(void) const
Definition: Anim_Blend.cpp:186
AFJointModType_t
Definition: Anim.h:457
const char * GetFileName(void) const
Definition: DeclManager.h:171
virtual bool Parse(const char *text, const int textLength)
const int * JointParents(void) const
const int DECL_LEXER_FLAGS
Definition: DeclManager.h:93
const jointInfo_t * FindJoint(const char *name) const
void Printf(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:699
void Zero(void)
Definition: Bounds.h:206
int NumAnims(void) const
void Clear(int currentTime, int clearTime)
const idEventDef AI_EnableEyeFocus("enableEyeFocus")
virtual idRenderModel * ANIM_CreateMeshForAnim(idRenderModel *model, const char *classname, const char *animname, int frame, bool remove_origin_offset)
idRenderModel * modelHandle
Definition: Anim.h:371
const idVec3 & TotalMovementDelta(void) const
Definition: Anim_Blend.cpp:221
void SetFrame(const idDeclModelDef *modelDef, int animnum, int frame, int currenttime, int blendtime)
virtual size_t Size(void) const
virtual int ANIM_GetNumAnimsFromEntityDef(const idDict *args)
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
bool SetSyncedAnimWeight(int num, float weight)
idMat3 ToMat3(void) const
Definition: Quat.cpp:70
const idEventDef EV_Activate("activate","e")
idRenderModel * ModelHandle(void) const
short frame
Definition: Anim.h:399
idRandom random
Definition: Game_local.h:291
int Length(void) const
Definition: Str.h:702
void void void void void Error(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:783
const int ANIMCHANNEL_ALL
Definition: Anim.h:41
int NumJoints(void) const
bool skipCinematic
Definition: Game_local.h:314
void GetBounds(idBounds &bounds, int currentTime, int cyclecount) const
Definition: Anim.cpp:589
const int ANIM_MaxSyncedAnims
Definition: Anim.h:36
const idEventDef AI_MuzzleFlash
int AFPoseTime
Definition: Anim.h:593
int Parse1DMatrix(int x, float *m)
Definition: Lexer.cpp:1300
const idEventDef AI_DisableGravity
idEntity * FindEntity(const char *name) const
bool AddBounds(int currentTime, idBounds &bounds, bool removeOriginOffset) const
float GetWeight(int currenttime) const
void AllowFrameCommands(bool allow)
const idEventDef AI_FireMissileAtTarget
float z
Definition: Vector.h:320
int AnimTime(int currenttime) const
virtual void FreeData(void)
float blendStartValue
Definition: Anim.h:394
const int ANIMCHANNEL_EYELIDS
Definition: Anim.h:45
const idEventDef AI_JumpFrame
bool ProcessEvent(const idEventDef *ev)
Definition: Class.cpp:858
void PlayAnim(int channelNum, int animnum, int currenttime, int blendTime)
float GetPlaybackRate(void) const
int subtype
Definition: Token.h:78
void SetGranularity(int newgranularity)
Definition: List.h:305
bool CreateFrame(int animtime, bool force)
const idEventDef EV_EnableLegIK("EnableLegIK","d")
int FindFrameForFrameCommand(frameCommandType_t framecommand, const frameCommand_t **command) const
const idDeclSkin * skin
Definition: Anim.h:169
jointHandle_t GetJointHandle(const char *name) const
const idDeclSkin * skin
Definition: Anim.h:373
int NumSyncedAnims(int animnum) const
idBounds frameBounds
Definition: Anim.h:586
const class idDeclModelDef * modelDef
Definition: Anim.h:386
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
void ReadBool(bool &value)
Definition: SaveGame.cpp:976
Definition: Anim.h:140
void BlendDelta(int fromtime, int totime, idVec3 &blendDelta, float &blendWeight) const
type * Ptr(void)
Definition: List.h:596
const char * AnimName(int animnum) const
idStr name
Definition: Anim.h:285
const char * Left(int len, idStr &result) const
Definition: Str.h:892
bool FrameHasChanged(int currentTime) const
virtual const char * Name() const =0
idList< idAnim * > anims
Definition: Anim.h:372
idCVar r_showSkel("r_showSkel","0", CVAR_RENDERER|CVAR_INTEGER,"draw the skeleton when model animates, 1 = draw model with skeleton, 2 = draw skeleton only", 0, 2, idCmdSystem::ArgCompletion_Integer< 0, 2 >)
void Clear(void)
Definition: Bounds.h:201
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
void InitAFPose(void)
const idDeclSkin * GetSkin(void) const
void GetOrigin(int currentTime, idVec3 &pos) const
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
Definition: Token.h:71
void SetJointPos(jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos)
void SetFlags(int flags)
Definition: Lexer.h:298
const idEventDef AI_EnableClip
void GetOrigin(idVec3 &offset, int currentTime, int cyclecount) const
Definition: Anim.cpp:434
int frame1
Definition: Anim.h:62
int NumJointsOnChannel(int channel) const
idVec3 offset
Definition: Anim.h:367
GLuint src
Definition: glext.h:5390
const idDeclModelDef * modelDef
Definition: Anim.h:573
GLenum GLsizei len
Definition: glext.h:3472
void Identity(void)
Definition: Matrix.h:591
bool BlendAnim(int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOrigin, bool overrideBlend, bool printInfo) const
int ReadTokenOnLine(idToken *token)
Definition: Lexer.cpp:1172
float x
Definition: Vector.h:318
void IncreaseRefs(void) const
Definition: Anim.cpp:335
idQuat & Slerp(const idQuat &from, const idQuat &to, float t)
Definition: Quat.cpp:160
bool HasFrameCommands(void) const
void CheckModelHierarchy(const idRenderModel *model) const
Definition: Anim.cpp:888
int i
Definition: process.py:33
void SetStartTime(int startTime)
const idVec3 & TotalMovementDelta(int animnum) const
const char * GetJointName(int jointHandle) const
int Cmpn(const char *text, int n) const
Definition: Str.h:657
int index
Definition: Anim.h:170
GLintptr offset
Definition: glext.h:3113
void SetAnim(const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ANIM_MaxSyncedAnims])
Definition: Anim_Blend.cpp:110
bool FrameHasChanged(int animtime) const
GLuint GLuint num
Definition: glext.h:5390
void Restore(idRestoreGame *savefile)
Boolean result
void WriteVec3(const idVec3 &vec)
Definition: SaveGame.cpp:253
void SetTranslation(const idVec3 &t)
const idEventDef AI_DisableClip
idList< int > channelJoints[ANIM_NumAnimChannels]
Definition: Anim.h:370
bool stoppedAnimatingUpdate
Definition: Anim.h:582
const jointInfo_t * GetJoint(int jointHandle) const
virtual void ANIM_CreateAnimFrame(const idRenderModel *model, const idMD5Anim *anim, int numJoints, idJointMat *frame, int time, const idVec3 &offset, bool remove_origin_offset)
void Reset(const idDeclModelDef *_modelDef)
void Set(float x, float y, float z, float w)
Definition: Quat.h:247
const idEventDef EV_EnableWalkIK("EnableWalkIK")
int Icmp(const char *text) const
Definition: Str.h:667
int blendDuration
Definition: Anim.h:393
idList< int > AFPoseJoints
Definition: Anim.h:589
bool GetBounds(idBounds &bounds, int animNum, int time, int cyclecount) const
Definition: Anim_Blend.cpp:264
idBounds AFPoseBounds
Definition: Anim.h:592
animFlags_t flags
Definition: Anim.h:289
void SetJointAxis(jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat)
virtual const char * ANIM_GetAnimNameFromEntityDef(const idDict *args, int animNum)
#define TT_NUMBER
Definition: Token.h:43
virtual void VPCALL ConvertJointMatsToJointQuats(idJointQuat *jointQuats, const idJointMat *jointMats, const int numJoints)=0
idProgram program
Definition: Game_local.h:293
void SetRotation(const idMat3 &m)
void WriteBool(const bool value)
Definition: SaveGame.cpp:222
static bool CharIsNumeric(int c)
Definition: Str.h:1024
void void void Warning(const char *fmt,...) const id_attribute((format(printf
Definition: Game_local.cpp:735
virtual const idMD5Joint * GetJoints(void) const =0
const idEventDef EV_DisableWalkIK("DisableWalkIK")
int AnimNum(void) const
const char * AnimName(void) const
virtual void BufferCommandText(cmdExecution_t exec, const char *text)=0
bool StartSoundShader(const idSoundShader *shader, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length)
Definition: Entity.cpp:1656
idList< frameCommand_t > frameCommands
Definition: Anim.h:288
void ClearAllJoints(void)
const char * AnimFullName(void) const
int GetFrameNumber(int currenttime) const
Definition: Lexer.h:137
int RandomInt(void)
Definition: Random.h:70
void Error(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:215
idRenderModel * SetModel(const char *modelname)
void GetDelta(int fromtime, int totime, idVec3 &delta) const
void CallFrameCommand(idEntity *ent, const function_t *frameCommand)
int endtime
Definition: Anim.h:388
virtual const char * GetJointName(jointHandle_t handle) const =0
GLuint GLuint GLsizei count
Definition: glext.h:2845
void WriteShort(const short value)
Definition: SaveGame.cpp:186
static const idEventDef * FindEvent(const char *name)
Definition: Event.cpp:192
const idEventDef EV_FootstepLeft("leftFoot")
jointModTransform_t
Definition: Anim.h:84
void RemoveOriginOffset(bool remove)
int blendStartTime
Definition: Anim.h:392
int PlayLength(void) const
const int ANIM_MaxAnimsPerChannel
Definition: Anim.h:35
idMD5Anim * GetAnim(const char *name)
Definition: Anim.cpp:953
const idDeclModelDef * ANIM_GetModelDefFromEntityDef(const idDict *args)
GLuint index
Definition: glext.h:3476
void SetSkin(const idDeclSkin *skin)
Definition: Entity.cpp:1178
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
void ReadFloat(float &value)
Definition: SaveGame.cpp:967
int Length(void) const
Definition: Anim.cpp:107
float RandomFloat(void)
Definition: Random.h:82
type & Alloc(void)
Definition: List.h:624
bool StartSound(const char *soundName, const s_channelType channel, int soundShaderFlags, bool broadcast, int *length)
Definition: Entity.cpp:1622
idVec3 vec3_origin(0.0f, 0.0f, 0.0f)
virtual void VPCALL BlendJoints(idJointQuat *joints, const idJointQuat *blendJoints, const float lerp, const int *index, const int numJoints)=0
void SetupJoints(int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset) const
#define vec3_zero
Definition: Vector.h:390
const idList< jointInfo_t > & Joints(void) const
const animFlags_t & GetAnimFlags(void) const
frameCommandType_t type
Definition: Anim.h:163
GLuint GLuint end
Definition: glext.h:2845
idVec3 ToVec3(void) const
void WriteFloat(const float value)
Definition: SaveGame.cpp:213
idCommon * common
Definition: Common.cpp:206
idJointMat * joints
Definition: RenderWorld.h:135
int Length(void) const
void ClearAllAnims(int currentTime, int cleartime)
Definition: Dict.h:65
#define NULL
Definition: Lib.h:88
void TriggerGuis(void)
Definition: Entity.cpp:3414
const idMD5Anim * MD5Anim(int num) const
Definition: Anim_Blend.cpp:165
const idMD5Joint * parent
Definition: Model.h:164
idAnimBlend * CurrentAnim(int channelNum)
const idDeclSkin * customSkin
Definition: RenderWorld.h:125
virtual idRenderModel * FindModel(const char *modelName)=0
void ReadModelDef(const idDeclModelDef *&modelDef)
Definition: SaveGame.cpp:1212
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)=0
idCVar g_debugBounds("g_debugBounds","0", CVAR_GAME|CVAR_BOOL,"checks for models with bounds > 2048")
float y
Definition: Vector.h:319
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
int GetInteger(void) const
Definition: CVarSystem.h:143
bool GetJointLocalTransform(jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis)
jointHandle_t num
Definition: Anim.h:76
void CapLength(int)
Definition: Str.h:859
void * Mem_Alloc16(const int size)
Definition: Heap.cpp:1107
const idAnim * GetAnim(int index) const
int NumAnims(void) const
Definition: Anim_Blend.cpp:212
idList< jointMod_t * > jointMods
Definition: Anim.h:577
void CycleAnim(int channelNum, int animnum, int currenttime, int blendtime)
idList< idJointQuat > AFPoseJointFrame
Definition: Anim.h:591
const idEventDef EV_DisableLegIK("DisableLegIK","d")
const int ANIM_NumAnimChannels
Definition: Anim.h:34
const float * ToFloatPtr(void) const
void GetJointList(const char *jointnames, idList< jointHandle_t > &jointList) const
void GetInterpolatedFrame(frameBlend_t &frame, idJointQuat *joints, const int *index, int numIndexes) const
Definition: Anim.cpp:630
const idEventDef AI_AttackMissile
bool GetOrigin(idVec3 &offset, int animNum, int time, int cyclecount) const
Definition: Anim_Blend.cpp:234
const char * FullName(void) const
Definition: Anim_Blend.cpp:154
Definition: Anim.h:137
virtual const idJointQuat * GetDefaultPose(void) const =0
void GetJointList(const char *jointnames, idList< jointHandle_t > &jointList) const
bool anim_turn
Definition: Anim.h:178
virtual idRenderModel * ANIM_GetModelFromName(const char *modelName)
int NumFrames(void) const
Definition: Anim_Blend.cpp:199
const char * Name(void) const
Definition: Anim.cpp:125
size_t Allocated(void) const
Definition: List.h:230
virtual int ANIM_GetNumFrames(const idMD5Anim *anim)
void DeleteContents(bool clear)
Definition: List.h:207
float GetFinalWeight(void) const
const char * Right(int len, idStr &result) const
Definition: Str.h:896
void ServiceAnims(int fromtime, int totime)
const idDeclModelDef * ModelDef(void) const
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
void CycleAnim(const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime)
int numAnims
Definition: Anim.h:284
idJointMat * joints
Definition: Anim.h:579
virtual void Reset()=0
void SetWeight(float newweight, int currenttime, int blendtime)
idGameLocal gameLocal
Definition: Game_local.cpp:64
void ForceUpdate(void)
int NumAnims(void) const
const animFlags_t GetAnimFlags(int animnum) const
const idEventDef EV_Footstep("footstep")
int GetCycleCount(void) const
void PushAnims(int channel, int currentTime, int blendTime)
void GetJoints(int *numJoints, idJointMat **jointsPtr)
const idVec3 & GetVisualOffset(void) const
const char * Name(void) const
Definition: Anim_Blend.cpp:145
const idDeclSkin * GetDefaultSkin(void) const
int LoadMemory(const char *ptr, int length, const char *name, int startLine=1)
Definition: Lexer.cpp:1646
idList< idAFPoseJointMod > AFPoseJointMods
Definition: Anim.h:590
bool forceUpdate
Definition: Anim.h:584
virtual idBounds Bounds(const struct renderEntity_s *ent=NULL) const =0
bool ai_no_turn
Definition: Anim.h:177
void ClearForceUpdate(void)
void Touch(void) const
virtual const idMD5Anim * ANIM_GetAnimFromEntityDef(const char *classname, const char *animname)
int GetNumArgs(void) const
Definition: Event.h:180
void Save(idSaveGame *savefile) const
void ReadBounds(idBounds &bounds)
Definition: SaveGame.cpp:1038
const class idDeclModelDef * modelDef
Definition: Anim.h:282
const idSoundShader * soundShader
Definition: Anim.h:167
int NumJoints(void) const
Definition: Anim.cpp:98
bool inCinematic
Definition: Game_local.h:313
void FreeData(void)
int lastTransformTime
Definition: Anim.h:581
void WriteInt(const int value)
Definition: SaveGame.cpp:168
const char * GetModelName(void) const
virtual void VPCALL Memcpy(void *dst, const void *src, const int count)=0
frameCommandType_t
Definition: Anim.h:107
idDeclManager * declManager
idVec3 pos
Definition: Anim.h:95
void WriteMat3(const idMat3 &mat)
Definition: SaveGame.cpp:309
virtual void VPCALL UntransformJoints(idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint)=0
bool IsDone(int currentTime) const
const idDeclModelDef * ModelDef(void) const
Definition: Anim_Blend.cpp:177
bool GetDeltaRotation(int fromtime, int totime, idMat3 &delta) const
GLubyte GLubyte b
Definition: glext.h:4662
void ReadMat3(idMat3 &mat)
Definition: SaveGame.cpp:1064
Definition: Quat.h:48
idMat3 ToMat3(void) const
jointModTransform_t transform_pos
Definition: Anim.h:96
const idEventDef AI_CreateMissile
virtual void VPCALL TransformJoints(idJointMat *jointMats, const int *parents, const int firstJoint, const int lastJoint)=0
jointHandle_t parentNum
Definition: Anim.h:77
int AnimLength(int animnum) const
int Insert(const type &obj, int index=0)
Definition: List.h:679
float rate
Definition: Anim.h:390
void CallObjectFrameCommand(idEntity *ent, const char *frameCommand)
int Append(const type &obj)
Definition: List.h:646
void void Warning(const char *str,...) id_attribute((format(printf
Definition: Lexer.cpp:241
bool HasAnim(const char *name) const
const idEventDef AI_TriggerParticles
float backlerp
Definition: Anim.h:65
virtual jointHandle_t GetJointHandle(const char *name) const =0
idEntity * entity
Definition: Anim.h:574
idRenderModelManager * renderModelManager
Definition: Matrix.h:333
static WindowRef ValidModeCallbackProc inCallback OSStatus err
void DecreaseRefs(void) const
Definition: Anim.cpp:344
virtual const idDecl * FindDeclWithoutParsing(declType_t type, const char *name, bool makeDefault=true)=0
virtual bool IsDefaultModel() const =0
virtual const char * DefaultDefinition(void) const
idStr * string
Definition: Anim.h:164
int AddUnique(const type &obj)
Definition: List.h:742
jointModTransform_t transform_axis
Definition: Anim.h:97
const char * AnimFullName(int animnum) const
bool GetBool(void) const
Definition: CVarSystem.h:142
void BlendDeltaRotation(int fromtime, int totime, idQuat &blendDelta, float &blendWeight) const
bool GetOriginRotation(idQuat &rotation, int animNum, int currentTime, int cyclecount) const
Definition: Anim_Blend.cpp:249
size_t Size(void) const
void PlayAnim(const idDeclModelDef *modelDef, int animnum, int currenttime, int blendtime)
tuple f
Definition: idal.py:89
short cycle
Definition: Anim.h:398
#define TT_PUNCTUATION
Definition: Token.h:45
bool IsCleared(void) const
Definition: Bounds.h:222
idAnimBlend channels[ANIM_NumAnimChannels][ANIM_MaxAnimsPerChannel]
Definition: Anim.h:576
float AFPoseBlendWeight
Definition: Anim.h:588
const idEventDef EV_FootstepRight("rightFoot")
idList< jointInfo_t > joints
Definition: Anim.h:368
virtual bool CanPlayChatterSounds(void) const
Definition: Entity.cpp:1613
#define MD5_MESH_EXT
Definition: Model.h:42
int Num(void) const
Definition: List.h:265
bool RemoveIndex(int index)
Definition: List.h:849
const idEventDef AI_EndAttack
void ReadShort(short &value)
Definition: SaveGame.cpp:940
declState_t GetState(void) const
Definition: DeclManager.h:146
const char * AddFrameCommand(const class idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def)
Definition: Anim_Blend.cpp:281
virtual int ANIM_GetLength(const idMD5Anim *anim)
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
void Signal(signalNum_t signalnum)
Definition: Entity.cpp:3352
idList< frameLookup_t > frameLookup
Definition: Anim.h:287
idList< int > jointParents
Definition: Anim.h:369
const idVec3 & TotalMovementDelta(void) const
Definition: Anim.cpp:116
void Mem_Free16(void *ptr)
Definition: Heap.cpp:1128
Definition: Str.h:116
idBounds bounds
Definition: RenderWorld.h:95
int starttime
Definition: Anim.h:387
int numJoints
Definition: Anim.h:578
bool BlendAFPose(idJointQuat *blendFrame) const
void AllowMovement(bool allow)
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
const char * GetName(void) const
Definition: Entity.cpp:875
Definition: Anim.h:124
virtual const idVec3 & ANIM_GetModelOffsetFromEntityDef(const char *classname)
void ReadVec3(idVec3 &vec)
Definition: SaveGame.cpp:1011
idStr name
Definition: Model.h:163
idAnimManager animationLib
Definition: Game_local.cpp:61
int suppressSurfaceInViewID
Definition: RenderWorld.h:104
int GetIntValue(void)
Definition: Token.h:152
const char * c_str(void) const
Definition: Str.h:487
int SkipUntilString(const char *string)
Definition: Lexer.cpp:1097
void CallFrameCommands(idEntity *ent, int fromtime, int totime) const
void SetAFPoseBlendWeight(float blendWeight)
void Clear(int channelNum, int currentTime, int cleartime)
int NumFrames(int animnum) const
const idAnim * GetAnim(int index) const
void ClearAFPose(void)
const idEventDef AI_AttackMelee
ID_INLINE int FRAME2MS(int framenum)
Definition: Anim.h:48
virtual const idMD5Anim * ANIM_GetAnim(const char *fileName)
const char * GetJointName(jointHandle_t handle) const
void BecomeActive(int flags)
Definition: Entity.cpp:995
virtual int NumJoints(void) const =0
void CallFrameCommands(idEntity *ent, int from, int to) const
Definition: Anim_Blend.cpp:721
void WriteBounds(const idBounds &bounds)
Definition: SaveGame.cpp:280
bool removeOriginOffset
Definition: Anim.h:583
function_t * FindFunction(const char *name) const
int GetEndTime(void) const
void SetFrame(int channelNum, int animnum, int frame, int currenttime, int blendtime)
idCVar g_debugAnim("g_debugAnim","-1", CVAR_GAME|CVAR_INTEGER,"displays information on which animations are playing on the specified entity number. set to -1 to disable.")
const idAnim * Anim(void) const
jointHandle_t jointnum
Definition: Anim.h:93
virtual const idDeclSkin * FindSkin(const char *name, bool makeDefault=true)=0
void WriteModelDef(const class idDeclModelDef *modelDef)
Definition: SaveGame.cpp:432
int NumFrames(void) const
idRenderModel * ModelHandle(void) const
bool prevent_idle_override
Definition: Anim.h:175
void GetSingleFrame(int framenum, idJointQuat *joints, const int *index, int numIndexes) const
Definition: Anim.cpp:820
int GetStartTime(void) const
GLint j
Definition: qgl.h:264
void GetOriginRotation(idQuat &rotation, int time, int cyclecount) const
Definition: Anim.cpp:474
void BlendOrigin(int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset) const
bool random_cycle_start
Definition: Anim.h:176
bool allowMove
Definition: Anim.h:401
Definition: Anim.h:121
const int * GetChannelJoints(int channel) const
const idDeclEntityDef * FindEntityDef(const char *name, bool makeDefault=true) const
#define TT_FLOAT
Definition: Token.h:55
idQuat Inverse(void) const
Definition: Quat.h:254
void CopyDecl(const idDeclModelDef *decl)
char * va(const char *fmt,...)
Definition: Str.cpp:1568
void ExtractFileExtension(idStr &dest) const
Definition: Str.cpp:965
static idEntityFx * StartFx(const char *fx, const idVec3 *useOrigin, const idMat3 *useAxis, idEntity *ent, bool bind)
Definition: Fx.cpp:716
int GetSpecificAnim(const char *name) const
void MakeDefault(void)
Definition: DeclManager.h:190
bool HasAnim(const char *name) const
virtual idRenderModel * ANIM_GetModelFromEntityDef(const char *classname)
float animWeights[ANIM_MaxSyncedAnims]
Definition: Anim.h:397
int entityNumber
Definition: Entity.h:111
idStr name
Definition: Entity.h:121
idEntity * GetEntity(void) const
idMat3 mat
Definition: Anim.h:94
void Zero(void)
Definition: Vector.h:415
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
size_t Allocated(void) const
void Restore(idRestoreGame *savefile, const idDeclModelDef *modelDef)
void SetAFPoseJointMod(const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin)
void BecomeInactive(int flags)
Definition: Entity.cpp:1025
const idJointQuat * GetDefaultPose(void) const
const function_t * function
Definition: Anim.h:168
int ReadToken(idToken *token)
Definition: Lexer.cpp:820
void ReadInt(int &value)
Definition: SaveGame.cpp:922
idStr realname
Definition: Anim.h:286
bool Remove(const type &obj)
Definition: List.h:878
void ConvertTimeToFrame(int time, int cyclecount, frameBlend_t &frame) const
Definition: Anim.cpp:384
Definition: Anim.h:280
void ClearJoint(jointHandle_t jointnum)
bool allowFrameCommands
Definition: Anim.h:402
void SetEntity(idEntity *ent)
int num
Definition: List.h:135
const idMD5Anim * anims[ANIM_MaxSyncedAnims]
Definition: Anim.h:283
void ReadObject(idClass *&obj)
Definition: SaveGame.cpp:1083
int NumSyncedAnims(void) const
const idEventDef AI_EnableGravity
size_t MemoryUsed(void) const
Definition: List.h:252
int NumFrames(void) const
Definition: Anim.cpp:89
GLdouble GLdouble t
Definition: glext.h:2943
bool RemoveOrigin(void) const
void Clear(void)
Definition: List.h:184
void SetPlaybackRate(int currentTime, float newRate)
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
short animNum
Definition: Anim.h:400