2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../Game_local.h"
34 static const char *channelNames[ ANIM_NumAnimChannels ] = {
35 "all", "torso", "legs", "head", "eyelids"
38 /***********************************************************************
42 ***********************************************************************/
52 memset( anims, 0, sizeof( anims ) );
53 memset( &flags, 0, sizeof( flags ) );
61 idAnim::idAnim( const idDeclModelDef *modelDef, const idAnim *anim ) {
64 this->modelDef = modelDef;
65 numAnims = anim->numAnims;
67 realname = anim->realname;
70 memset( anims, 0, sizeof( anims ) );
71 for( i = 0; i < numAnims; i++ ) {
72 anims[ i ] = anim->anims[ i ];
73 anims[ i ]->IncreaseRefs();
76 frameLookup.SetNum( anim->frameLookup.Num() );
77 memcpy( frameLookup.Ptr(), anim->frameLookup.Ptr(), frameLookup.MemoryUsed() );
79 frameCommands.SetNum( anim->frameCommands.Num() );
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 );
96 for( i = 0; i < numAnims; i++ ) {
97 anims[ i ]->DecreaseRefs();
100 for( i = 0; i < frameCommands.Num(); i++ ) {
101 delete frameCommands[ i ].string;
106 =====================
108 =====================
110 void idAnim::SetAnim( const idDeclModelDef *modelDef, const char *sourcename, const char *animname, int num, const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ] ) {
113 this->modelDef = modelDef;
115 for( i = 0; i < numAnims; i++ ) {
116 anims[ i ]->DecreaseRefs();
120 assert( ( num > 0 ) && ( num <= ANIM_MaxSyncedAnims ) );
122 realname = sourcename;
125 for( i = 0; i < num; i++ ) {
126 anims[ i ] = md5anims[ i ];
127 anims[ i ]->IncreaseRefs();
130 memset( &flags, 0, sizeof( flags ) );
132 for( i = 0; i < frameCommands.Num(); i++ ) {
133 delete frameCommands[ i ].string;
137 frameCommands.Clear();
141 =====================
143 =====================
145 const char *idAnim::Name( void ) const {
150 =====================
152 =====================
154 const char *idAnim::FullName( void ) const {
159 =====================
162 index 0 will never be NULL. Any anim >= NumAnims will return NULL.
163 =====================
165 const idMD5Anim *idAnim::MD5Anim( int num ) const {
166 if ( anims == NULL || anims[0] == NULL ) {
173 =====================
175 =====================
177 const idDeclModelDef *idAnim::ModelDef( void ) const {
182 =====================
184 =====================
186 int idAnim::Length( void ) const {
191 return anims[ 0 ]->Length();
195 =====================
197 =====================
199 int idAnim::NumFrames( void ) const {
204 return anims[ 0 ]->NumFrames();
208 =====================
210 =====================
212 int idAnim::NumAnims( void ) const {
217 =====================
218 idAnim::TotalMovementDelta
219 =====================
221 const idVec3 &idAnim::TotalMovementDelta( void ) const {
226 return anims[ 0 ]->TotalMovementDelta();
230 =====================
232 =====================
234 bool idAnim::GetOrigin( idVec3 &offset, int animNum, int currentTime, int cyclecount ) const {
235 if ( !anims[ animNum ] ) {
240 anims[ animNum ]->GetOrigin( offset, currentTime, cyclecount );
245 =====================
246 idAnim::GetOriginRotation
247 =====================
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 );
255 anims[ animNum ]->GetOriginRotation( rotation, currentTime, cyclecount );
260 =====================
262 =====================
264 ID_INLINE bool idAnim::GetBounds( idBounds &bounds, int animNum, int currentTime, int cyclecount ) const {
265 if ( !anims[ animNum ] ) {
269 anims[ animNum ]->GetBounds( bounds, currentTime, cyclecount );
275 =====================
276 idAnim::AddFrameCommand
278 Returns NULL if no error.
279 =====================
281 const char *idAnim::AddFrameCommand( const idDeclModelDef *modelDef, int framenum, idLexer &src, const idDict *def ) {
288 const jointInfo_t *jointInfo;
290 // make sure we're within bounds
291 if ( ( framenum < 1 ) || ( framenum > anims[ 0 ]->NumFrames() ) ) {
292 return va( "Frame %d out of range", framenum );
295 // frame numbers are 1 based in .def files, but 0 based internally
298 memset( &fc, 0, sizeof( fc ) );
300 if( !src.ReadTokenOnLine( &token ) ) {
301 return "Unexpected end of line";
303 if ( token == "call" ) {
304 if( !src.ReadTokenOnLine( &token ) ) {
305 return "Unexpected end of line";
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() );
312 } else if ( token == "object_call" ) {
313 if( !src.ReadTokenOnLine( &token ) ) {
314 return "Unexpected end of line";
316 fc.type = FC_SCRIPTFUNCTIONOBJECT;
317 fc.string = new idStr( token );
318 } else if ( token == "event" ) {
319 if( !src.ReadTokenOnLine( &token ) ) {
320 return "Unexpected end of line";
322 fc.type = FC_EVENTFUNCTION;
323 const idEventDef *ev = idEventDef::FindEvent( token );
325 return va( "Event '%s' not found", token.c_str() );
327 if ( ev->GetNumArgs() != 0 ) {
328 return va( "Event '%s' has arguments", token.c_str() );
330 fc.string = new idStr( token );
331 } else if ( token == "sound" ) {
332 if( !src.ReadTokenOnLine( &token ) ) {
333 return "Unexpected end of line";
336 if ( !token.Cmpn( "snd_", 4 ) ) {
337 fc.string = new idStr( token );
339 fc.soundShader = declManager->FindSound( token );
340 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
341 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
344 } else if ( token == "sound_voice" ) {
345 if( !src.ReadTokenOnLine( &token ) ) {
346 return "Unexpected end of line";
348 fc.type = FC_SOUND_VOICE;
349 if ( !token.Cmpn( "snd_", 4 ) ) {
350 fc.string = new idStr( token );
352 fc.soundShader = declManager->FindSound( token );
353 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
354 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
357 } else if ( token == "sound_voice2" ) {
358 if( !src.ReadTokenOnLine( &token ) ) {
359 return "Unexpected end of line";
361 fc.type = FC_SOUND_VOICE2;
362 if ( !token.Cmpn( "snd_", 4 ) ) {
363 fc.string = new idStr( token );
365 fc.soundShader = declManager->FindSound( token );
366 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
367 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
370 } else if ( token == "sound_body" ) {
371 if( !src.ReadTokenOnLine( &token ) ) {
372 return "Unexpected end of line";
374 fc.type = FC_SOUND_BODY;
375 if ( !token.Cmpn( "snd_", 4 ) ) {
376 fc.string = new idStr( token );
378 fc.soundShader = declManager->FindSound( token );
379 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
380 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
383 } else if ( token == "sound_body2" ) {
384 if( !src.ReadTokenOnLine( &token ) ) {
385 return "Unexpected end of line";
387 fc.type = FC_SOUND_BODY2;
388 if ( !token.Cmpn( "snd_", 4 ) ) {
389 fc.string = new idStr( token );
391 fc.soundShader = declManager->FindSound( token );
392 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
393 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
396 } else if ( token == "sound_body3" ) {
397 if( !src.ReadTokenOnLine( &token ) ) {
398 return "Unexpected end of line";
400 fc.type = FC_SOUND_BODY3;
401 if ( !token.Cmpn( "snd_", 4 ) ) {
402 fc.string = new idStr( token );
404 fc.soundShader = declManager->FindSound( token );
405 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
406 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
409 } else if ( token == "sound_weapon" ) {
410 if( !src.ReadTokenOnLine( &token ) ) {
411 return "Unexpected end of line";
413 fc.type = FC_SOUND_WEAPON;
414 if ( !token.Cmpn( "snd_", 4 ) ) {
415 fc.string = new idStr( token );
417 fc.soundShader = declManager->FindSound( token );
418 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
419 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
422 } else if ( token == "sound_global" ) {
423 if( !src.ReadTokenOnLine( &token ) ) {
424 return "Unexpected end of line";
426 fc.type = FC_SOUND_GLOBAL;
427 if ( !token.Cmpn( "snd_", 4 ) ) {
428 fc.string = new idStr( token );
430 fc.soundShader = declManager->FindSound( token );
431 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
432 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
435 } else if ( token == "sound_item" ) {
436 if( !src.ReadTokenOnLine( &token ) ) {
437 return "Unexpected end of line";
439 fc.type = FC_SOUND_ITEM;
440 if ( !token.Cmpn( "snd_", 4 ) ) {
441 fc.string = new idStr( token );
443 fc.soundShader = declManager->FindSound( token );
444 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
445 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
448 } else if ( token == "sound_chatter" ) {
449 if( !src.ReadTokenOnLine( &token ) ) {
450 return "Unexpected end of line";
452 fc.type = FC_SOUND_CHATTER;
453 if ( !token.Cmpn( "snd_", 4 ) ) {
454 fc.string = new idStr( token );
456 fc.soundShader = declManager->FindSound( token );
457 if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
458 gameLocal.Warning( "Sound '%s' not found", token.c_str() );
461 } else if ( token == "skin" ) {
462 if( !src.ReadTokenOnLine( &token ) ) {
463 return "Unexpected end of line";
466 if ( token == "none" ) {
469 fc.skin = declManager->FindSkin( token );
471 return va( "Skin '%s' not found", token.c_str() );
474 } else if ( token == "fx" ) {
475 if( !src.ReadTokenOnLine( &token ) ) {
476 return "Unexpected end of line";
479 if ( !declManager->FindType( DECL_FX, token.c_str() ) ) {
480 return va( "fx '%s' not found", token.c_str() );
482 fc.string = new idStr( token );
483 } else if ( token == "trigger" ) {
484 if( !src.ReadTokenOnLine( &token ) ) {
485 return "Unexpected end of line";
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";
493 fc.type = FC_TRIGGER_SMOKE_PARTICLE;
494 fc.string = new idStr( token );
495 } else if ( token == "melee" ) {
496 if( !src.ReadTokenOnLine( &token ) ) {
497 return "Unexpected end of line";
500 if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
501 return va( "Unknown entityDef '%s'", token.c_str() );
503 fc.string = new idStr( token );
504 } else if ( token == "direct_damage" ) {
505 if( !src.ReadTokenOnLine( &token ) ) {
506 return "Unexpected end of line";
508 fc.type = FC_DIRECTDAMAGE;
509 if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
510 return va( "Unknown entityDef '%s'", token.c_str() );
512 fc.string = new idStr( token );
513 } else if ( token == "attack_begin" ) {
514 if( !src.ReadTokenOnLine( &token ) ) {
515 return "Unexpected end of line";
517 fc.type = FC_BEGINATTACK;
518 if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
519 return va( "Unknown entityDef '%s'", token.c_str() );
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";
528 if ( ( token != "" ) && !modelDef->FindJoint( token ) ) {
529 return va( "Joint '%s' not found", token.c_str() );
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";
540 if ( !modelDef->FindJoint( token ) ) {
541 return va( "Joint '%s' not found", token.c_str() );
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";
549 if ( !modelDef->FindJoint( token ) ) {
550 return va( "Joint '%s' not found", token.c_str() );
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";
558 jointInfo = modelDef->FindJoint( token );
560 return va( "Joint '%s' not found", token.c_str() );
562 if( !src.ReadTokenOnLine( &token ) ) {
563 return "Unexpected end of line";
565 fc.type = FC_FIREMISSILEATTARGET;
566 fc.string = new idStr( token );
567 fc.index = jointInfo->num;
568 } else if ( token == "footstep" ) {
569 fc.type = FC_FOOTSTEP;
570 } else if ( token == "leftfoot" ) {
571 fc.type = FC_LEFTFOOT;
572 } else if ( token == "rightfoot" ) {
573 fc.type = FC_RIGHTFOOT;
574 } else if ( token == "enableEyeFocus" ) {
575 fc.type = FC_ENABLE_EYE_FOCUS;
576 } else if ( token == "disableEyeFocus" ) {
577 fc.type = FC_DISABLE_EYE_FOCUS;
578 } else if ( token == "disableGravity" ) {
579 fc.type = FC_DISABLE_GRAVITY;
580 } else if ( token == "enableGravity" ) {
581 fc.type = FC_ENABLE_GRAVITY;
582 } else if ( token == "jump" ) {
584 } else if ( token == "enableClip" ) {
585 fc.type = FC_ENABLE_CLIP;
586 } else if ( token == "disableClip" ) {
587 fc.type = FC_DISABLE_CLIP;
588 } else if ( token == "enableWalkIK" ) {
589 fc.type = FC_ENABLE_WALK_IK;
590 } else if ( token == "disableWalkIK" ) {
591 fc.type = FC_DISABLE_WALK_IK;
592 } else if ( token == "enableLegIK" ) {
593 if( !src.ReadTokenOnLine( &token ) ) {
594 return "Unexpected end of line";
596 fc.type = FC_ENABLE_LEG_IK;
597 fc.index = atoi( token );
598 } else if ( token == "disableLegIK" ) {
599 if( !src.ReadTokenOnLine( &token ) ) {
600 return "Unexpected end of line";
602 fc.type = FC_DISABLE_LEG_IK;
603 fc.index = atoi( token );
604 } else if ( token == "recordDemo" ) {
605 fc.type = FC_RECORDDEMO;
606 if( src.ReadTokenOnLine( &token ) ) {
607 fc.string = new idStr( token );
609 } else if ( token == "aviGame" ) {
610 fc.type = FC_AVIGAME;
611 if( src.ReadTokenOnLine( &token ) ) {
612 fc.string = new idStr( token );
615 return va( "Unknown command '%s'", token.c_str() );
618 // check if we've initialized the frame loopup table
619 if ( !frameLookup.Num() ) {
620 // we haven't, so allocate the table and initialize it
621 frameLookup.SetGranularity( 1 );
622 frameLookup.SetNum( anims[ 0 ]->NumFrames() );
623 for( i = 0; i < frameLookup.Num(); i++ ) {
624 frameLookup[ i ].num = 0;
625 frameLookup[ i ].firstCommand = 0;
629 // allocate space for a new command
630 frameCommands.Alloc();
632 // calculate the index of the new command
633 index = frameLookup[ framenum ].firstCommand + frameLookup[ framenum ].num;
635 // move all commands from our index onward up one to give us space for our new command
636 for( i = frameCommands.Num() - 1; i > index; i-- ) {
637 frameCommands[ i ] = frameCommands[ i - 1 ];
640 // fix the indices of any later frames to account for the inserted command
641 for( i = framenum + 1; i < frameLookup.Num(); i++ ) {
642 frameLookup[ i ].firstCommand++;
645 // store the new command
646 frameCommands[ index ] = fc;
648 // increase the number of commands on this frame
649 frameLookup[ framenum ].num++;
651 // return with no error
656 =====================
657 idAnim::CallFrameCommands
658 =====================
660 void idAnim::CallFrameCommands( idEntity *ent, int from, int to ) const {
666 numframes = anims[ 0 ]->NumFrames();
669 while( frame != to ) {
671 if ( frame >= numframes ) {
675 index = frameLookup[ frame ].firstCommand;
676 end = index + frameLookup[ frame ].num;
677 while( index < end ) {
678 const frameCommand_t &command = frameCommands[ index++ ];
679 switch( command.type ) {
680 case FC_SCRIPTFUNCTION: {
681 gameLocal.CallFrameCommand( ent, command.function );
684 case FC_SCRIPTFUNCTIONOBJECT: {
685 gameLocal.CallObjectFrameCommand( ent, command.string->c_str() );
688 case FC_EVENTFUNCTION: {
689 const idEventDef *ev = idEventDef::FindEvent( command.string->c_str() );
690 ent->ProcessEvent( ev );
694 if ( !command.soundShader ) {
695 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, 0, false, NULL ) ) {
696 gameLocal.Warning( "Framecommand 'sound' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
697 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
700 ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, 0, false, NULL );
704 case FC_SOUND_VOICE: {
705 if ( !command.soundShader ) {
706 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) {
707 gameLocal.Warning( "Framecommand 'sound_voice' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
708 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
711 ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL );
715 case FC_SOUND_VOICE2: {
716 if ( !command.soundShader ) {
717 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE2, 0, false, NULL ) ) {
718 gameLocal.Warning( "Framecommand 'sound_voice2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
719 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
722 ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE2, 0, false, NULL );
726 case FC_SOUND_BODY: {
727 if ( !command.soundShader ) {
728 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY, 0, false, NULL ) ) {
729 gameLocal.Warning( "Framecommand 'sound_body' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
730 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
733 ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY, 0, false, NULL );
737 case FC_SOUND_BODY2: {
738 if ( !command.soundShader ) {
739 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY2, 0, false, NULL ) ) {
740 gameLocal.Warning( "Framecommand 'sound_body2' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
741 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
744 ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY2, 0, false, NULL );
748 case FC_SOUND_BODY3: {
749 if ( !command.soundShader ) {
750 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_BODY3, 0, false, NULL ) ) {
751 gameLocal.Warning( "Framecommand 'sound_body3' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
752 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
755 ent->StartSoundShader( command.soundShader, SND_CHANNEL_BODY3, 0, false, NULL );
759 case FC_SOUND_WEAPON: {
760 if ( !command.soundShader ) {
761 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_WEAPON, 0, false, NULL ) ) {
762 gameLocal.Warning( "Framecommand 'sound_weapon' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
763 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
766 ent->StartSoundShader( command.soundShader, SND_CHANNEL_WEAPON, 0, false, NULL );
770 case FC_SOUND_GLOBAL: {
771 if ( !command.soundShader ) {
772 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL ) ) {
773 gameLocal.Warning( "Framecommand 'sound_global' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
774 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
777 ent->StartSoundShader( command.soundShader, SND_CHANNEL_ANY, SSF_GLOBAL, false, NULL );
781 case FC_SOUND_ITEM: {
782 if ( !command.soundShader ) {
783 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_ITEM, 0, false, NULL ) ) {
784 gameLocal.Warning( "Framecommand 'sound_item' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
785 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
788 ent->StartSoundShader( command.soundShader, SND_CHANNEL_ITEM, 0, false, NULL );
792 case FC_SOUND_CHATTER: {
793 if ( ent->CanPlayChatterSounds() ) {
794 if ( !command.soundShader ) {
795 if ( !ent->StartSound( command.string->c_str(), SND_CHANNEL_VOICE, 0, false, NULL ) ) {
796 gameLocal.Warning( "Framecommand 'sound_chatter' on entity '%s', anim '%s', frame %d: Could not find sound '%s'",
797 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
800 ent->StartSoundShader( command.soundShader, SND_CHANNEL_VOICE, 0, false, NULL );
806 idEntityFx::StartFx( command.string->c_str(), NULL, NULL, ent, true );
810 ent->SetSkin( command.skin );
816 target = gameLocal.FindEntity( command.string->c_str() );
818 target->Signal( SIG_TRIGGER );
819 target->ProcessEvent( &EV_Activate, ent );
820 target->TriggerGuis();
822 gameLocal.Warning( "Framecommand 'trigger' on entity '%s', anim '%s', frame %d: Could not find entity '%s'",
823 ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
827 case FC_TRIGGER_SMOKE_PARTICLE: {
828 ent->ProcessEvent( &AI_TriggerParticles, command.string->c_str() );
832 ent->ProcessEvent( &AI_AttackMelee, command.string->c_str() );
835 case FC_DIRECTDAMAGE: {
836 ent->ProcessEvent( &AI_DirectDamage, command.string->c_str() );
839 case FC_BEGINATTACK: {
840 ent->ProcessEvent( &AI_BeginAttack, command.string->c_str() );
844 ent->ProcessEvent( &AI_EndAttack );
847 case FC_MUZZLEFLASH: {
848 ent->ProcessEvent( &AI_MuzzleFlash, command.string->c_str() );
851 case FC_CREATEMISSILE: {
852 ent->ProcessEvent( &AI_CreateMissile, command.string->c_str() );
855 case FC_LAUNCHMISSILE: {
856 ent->ProcessEvent( &AI_AttackMissile, command.string->c_str() );
859 case FC_FIREMISSILEATTARGET: {
860 ent->ProcessEvent( &AI_FireMissileAtTarget, modelDef->GetJointName( command.index ), command.string->c_str() );
864 ent->ProcessEvent( &EV_Footstep );
868 ent->ProcessEvent( &EV_FootstepLeft );
872 ent->ProcessEvent( &EV_FootstepRight );
875 case FC_ENABLE_EYE_FOCUS: {
876 ent->ProcessEvent( &AI_EnableEyeFocus );
879 case FC_DISABLE_EYE_FOCUS: {
880 ent->ProcessEvent( &AI_DisableEyeFocus );
883 case FC_DISABLE_GRAVITY: {
884 ent->ProcessEvent( &AI_DisableGravity );
887 case FC_ENABLE_GRAVITY: {
888 ent->ProcessEvent( &AI_EnableGravity );
892 ent->ProcessEvent( &AI_JumpFrame );
895 case FC_ENABLE_CLIP: {
896 ent->ProcessEvent( &AI_EnableClip );
899 case FC_DISABLE_CLIP: {
900 ent->ProcessEvent( &AI_DisableClip );
903 case FC_ENABLE_WALK_IK: {
904 ent->ProcessEvent( &EV_EnableWalkIK );
907 case FC_DISABLE_WALK_IK: {
908 ent->ProcessEvent( &EV_DisableWalkIK );
911 case FC_ENABLE_LEG_IK: {
912 ent->ProcessEvent( &EV_EnableLegIK, command.index );
915 case FC_DISABLE_LEG_IK: {
916 ent->ProcessEvent( &EV_DisableLegIK, command.index );
919 case FC_RECORDDEMO: {
920 if ( command.string ) {
921 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "recordDemo %s", command.string->c_str() ) );
923 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "stoprecording" );
928 if ( command.string ) {
929 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "aviGame %s", command.string->c_str() ) );
931 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "aviGame" );
941 =====================
942 idAnim::FindFrameForFrameCommand
943 =====================
945 int idAnim::FindFrameForFrameCommand( frameCommandType_t framecommand, const frameCommand_t **command ) const {
951 if ( !frameCommands.Num() ) {
955 numframes = anims[ 0 ]->NumFrames();
956 for( frame = 0; frame < numframes; frame++ ) {
957 end = frameLookup[ frame ].firstCommand + frameLookup[ frame ].num;
958 for( index = frameLookup[ frame ].firstCommand; index < end; index++ ) {
959 if ( frameCommands[ index ].type == framecommand ) {
961 *command = &frameCommands[ index ];
976 =====================
977 idAnim::HasFrameCommands
978 =====================
980 bool idAnim::HasFrameCommands( void ) const {
981 if ( !frameCommands.Num() ) {
988 =====================
990 =====================
992 void idAnim::SetAnimFlags( const animFlags_t &animflags ) {
997 =====================
999 =====================
1001 const animFlags_t &idAnim::GetAnimFlags( void ) const {
1005 /***********************************************************************
1009 ***********************************************************************/
1012 =====================
1013 idAnimBlend::idAnimBlend
1014 =====================
1016 idAnimBlend::idAnimBlend( void ) {
1021 =====================
1024 archives object for save game file
1025 =====================
1027 void idAnimBlend::Save( idSaveGame *savefile ) const {
1030 savefile->WriteInt( starttime );
1031 savefile->WriteInt( endtime );
1032 savefile->WriteInt( timeOffset );
1033 savefile->WriteFloat( rate );
1035 savefile->WriteInt( blendStartTime );
1036 savefile->WriteInt( blendDuration );
1037 savefile->WriteFloat( blendStartValue );
1038 savefile->WriteFloat( blendEndValue );
1040 for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) {
1041 savefile->WriteFloat( animWeights[ i ] );
1043 savefile->WriteShort( cycle );
1044 savefile->WriteShort( frame );
1045 savefile->WriteShort( animNum );
1046 savefile->WriteBool( allowMove );
1047 savefile->WriteBool( allowFrameCommands );
1051 =====================
1052 idAnimBlend::Restore
1054 unarchives object from save game file
1055 =====================
1057 void idAnimBlend::Restore( idRestoreGame *savefile, const idDeclModelDef *modelDef ) {
1060 this->modelDef = modelDef;
1062 savefile->ReadInt( starttime );
1063 savefile->ReadInt( endtime );
1064 savefile->ReadInt( timeOffset );
1065 savefile->ReadFloat( rate );
1067 savefile->ReadInt( blendStartTime );
1068 savefile->ReadInt( blendDuration );
1069 savefile->ReadFloat( blendStartValue );
1070 savefile->ReadFloat( blendEndValue );
1072 for( i = 0; i < ANIM_MaxSyncedAnims; i++ ) {
1073 savefile->ReadFloat( animWeights[ i ] );
1075 savefile->ReadShort( cycle );
1076 savefile->ReadShort( frame );
1077 savefile->ReadShort( animNum );
1080 } else if ( ( animNum < 0 ) || ( animNum > modelDef->NumAnims() ) ) {
1081 gameLocal.Warning( "Anim number %d out of range for model '%s' during save game", animNum, modelDef->GetModelName() );
1084 savefile->ReadBool( allowMove );
1085 savefile->ReadBool( allowFrameCommands );
1089 =====================
1091 =====================
1093 void idAnimBlend::Reset( const idDeclModelDef *_modelDef ) {
1094 modelDef = _modelDef;
1102 allowFrameCommands = true;
1105 memset( animWeights, 0, sizeof( animWeights ) );
1107 blendStartValue = 0.0f;
1108 blendEndValue = 0.0f;
1114 =====================
1115 idAnimBlend::FullName
1116 =====================
1118 const char *idAnimBlend::AnimFullName( void ) const {
1119 const idAnim *anim = Anim();
1124 return anim->FullName();
1128 =====================
1129 idAnimBlend::AnimName
1130 =====================
1132 const char *idAnimBlend::AnimName( void ) const {
1133 const idAnim *anim = Anim();
1138 return anim->Name();
1142 =====================
1143 idAnimBlend::NumFrames
1144 =====================
1146 int idAnimBlend::NumFrames( void ) const {
1147 const idAnim *anim = Anim();
1152 return anim->NumFrames();
1156 =====================
1158 =====================
1160 int idAnimBlend::Length( void ) const {
1161 const idAnim *anim = Anim();
1166 return anim->Length();
1170 =====================
1171 idAnimBlend::GetWeight
1172 =====================
1174 float idAnimBlend::GetWeight( int currentTime ) const {
1179 timeDelta = currentTime - blendStartTime;
1180 if ( timeDelta <= 0 ) {
1181 w = blendStartValue;
1182 } else if ( timeDelta >= blendDuration ) {
1185 frac = ( float )timeDelta / ( float )blendDuration;
1186 w = blendStartValue + ( blendEndValue - blendStartValue ) * frac;
1193 =====================
1194 idAnimBlend::GetFinalWeight
1195 =====================
1197 float idAnimBlend::GetFinalWeight( void ) const {
1198 return blendEndValue;
1202 =====================
1203 idAnimBlend::SetWeight
1204 =====================
1206 void idAnimBlend::SetWeight( float newweight, int currentTime, int blendTime ) {
1207 blendStartValue = GetWeight( currentTime );
1208 blendEndValue = newweight;
1209 blendStartTime = currentTime - 1;
1210 blendDuration = blendTime;
1213 endtime = currentTime + blendTime;
1218 =====================
1219 idAnimBlend::NumSyncedAnims
1220 =====================
1222 int idAnimBlend::NumSyncedAnims( void ) const {
1223 const idAnim *anim = Anim();
1228 return anim->NumAnims();
1232 =====================
1233 idAnimBlend::SetSyncedAnimWeight
1234 =====================
1236 bool idAnimBlend::SetSyncedAnimWeight( int num, float weight ) {
1237 const idAnim *anim = Anim();
1242 if ( ( num < 0 ) || ( num > anim->NumAnims() ) ) {
1246 animWeights[ num ] = weight;
1251 =====================
1252 idAnimBlend::SetFrame
1253 =====================
1255 void idAnimBlend::SetFrame( const idDeclModelDef *modelDef, int _animNum, int _frame, int currentTime, int blendTime ) {
1261 const idAnim *_anim = modelDef->GetAnim( _animNum );
1266 const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1267 if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1268 gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1273 starttime = currentTime;
1276 animWeights[ 0 ] = 1.0f;
1279 // a frame of 0 means it's not a single frame blend, so we set it to frame + 1
1282 } else if ( frame > _anim->NumFrames() ) {
1283 frame = _anim->NumFrames();
1287 blendEndValue = 1.0f;
1288 blendStartTime = currentTime - 1;
1289 blendDuration = blendTime;
1290 blendStartValue = 0.0f;
1294 =====================
1295 idAnimBlend::CycleAnim
1296 =====================
1298 void idAnimBlend::CycleAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) {
1304 const idAnim *_anim = modelDef->GetAnim( _animNum );
1309 const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1310 if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1311 gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1316 animWeights[ 0 ] = 1.0f;
1319 if ( _anim->GetAnimFlags().random_cycle_start ) {
1320 // start the animation at a random time so that characters don't walk in sync
1321 starttime = currentTime - gameLocal.random.RandomFloat() * _anim->Length();
1323 starttime = currentTime;
1327 blendEndValue = 1.0f;
1328 blendStartTime = currentTime - 1;
1329 blendDuration = blendTime;
1330 blendStartValue = 0.0f;
1334 =====================
1335 idAnimBlend::PlayAnim
1336 =====================
1338 void idAnimBlend::PlayAnim( const idDeclModelDef *modelDef, int _animNum, int currentTime, int blendTime ) {
1344 const idAnim *_anim = modelDef->GetAnim( _animNum );
1349 const idMD5Anim *md5anim = _anim->MD5Anim( 0 );
1350 if ( modelDef->Joints().Num() != md5anim->NumJoints() ) {
1351 gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", modelDef->GetModelName(), md5anim->Name() );
1356 starttime = currentTime;
1357 endtime = starttime + _anim->Length();
1359 animWeights[ 0 ] = 1.0f;
1362 blendEndValue = 1.0f;
1363 blendStartTime = currentTime - 1;
1364 blendDuration = blendTime;
1365 blendStartValue = 0.0f;
1369 =====================
1371 =====================
1373 void idAnimBlend::Clear( int currentTime, int clearTime ) {
1377 SetWeight( 0.0f, currentTime, clearTime );
1382 =====================
1384 =====================
1386 bool idAnimBlend::IsDone( int currentTime ) const {
1387 if ( !frame && ( endtime > 0 ) && ( currentTime >= endtime ) ) {
1391 if ( ( blendEndValue <= 0.0f ) && ( currentTime >= ( blendStartTime + blendDuration ) ) ) {
1399 =====================
1400 idAnimBlend::FrameHasChanged
1401 =====================
1403 bool idAnimBlend::FrameHasChanged( int currentTime ) const {
1404 // if we don't have an anim, no change
1409 // if anim is done playing, no change
1410 if ( ( endtime > 0 ) && ( currentTime > endtime ) ) {
1414 // if our blend weight changes, we need to update
1415 if ( ( currentTime < ( blendStartTime + blendDuration ) && ( blendStartValue != blendEndValue ) ) ) {
1419 // if we're a single frame anim and this isn't the frame we started on, we don't need to update
1420 if ( ( frame || ( NumFrames() == 1 ) ) && ( currentTime != starttime ) ) {
1428 =====================
1429 idAnimBlend::GetCycleCount
1430 =====================
1432 int idAnimBlend::GetCycleCount( void ) const {
1437 =====================
1438 idAnimBlend::SetCycleCount
1439 =====================
1441 void idAnimBlend::SetCycleCount( int count ) {
1442 const idAnim *anim = Anim();
1452 } else if ( cycle == 0 ) {
1455 // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1456 if ( rate == 1.0f ) {
1457 endtime = starttime - timeOffset + anim->Length();
1458 } else if ( rate != 0.0f ) {
1459 endtime = starttime - timeOffset + anim->Length() / rate;
1464 // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1465 if ( rate == 1.0f ) {
1466 endtime = starttime - timeOffset + anim->Length() * cycle;
1467 } else if ( rate != 0.0f ) {
1468 endtime = starttime - timeOffset + ( anim->Length() * cycle ) / rate;
1477 =====================
1478 idAnimBlend::SetPlaybackRate
1479 =====================
1481 void idAnimBlend::SetPlaybackRate( int currentTime, float newRate ) {
1484 if ( rate == newRate ) {
1488 animTime = AnimTime( currentTime );
1489 if ( newRate == 1.0f ) {
1490 timeOffset = animTime - ( currentTime - starttime );
1492 timeOffset = animTime - ( currentTime - starttime ) * newRate;
1497 // update the anim endtime
1498 SetCycleCount( cycle );
1502 =====================
1503 idAnimBlend::GetPlaybackRate
1504 =====================
1506 float idAnimBlend::GetPlaybackRate( void ) const {
1511 =====================
1512 idAnimBlend::SetStartTime
1513 =====================
1515 void idAnimBlend::SetStartTime( int _startTime ) {
1516 starttime = _startTime;
1518 // update the anim endtime
1519 SetCycleCount( cycle );
1523 =====================
1524 idAnimBlend::GetStartTime
1525 =====================
1527 int idAnimBlend::GetStartTime( void ) const {
1536 =====================
1537 idAnimBlend::GetEndTime
1538 =====================
1540 int idAnimBlend::GetEndTime( void ) const {
1549 =====================
1550 idAnimBlend::PlayLength
1551 =====================
1553 int idAnimBlend::PlayLength( void ) const {
1558 if ( endtime < 0 ) {
1562 return endtime - starttime + timeOffset;
1566 =====================
1567 idAnimBlend::AllowMovement
1568 =====================
1570 void idAnimBlend::AllowMovement( bool allow ) {
1575 =====================
1576 idAnimBlend::AllowFrameCommands
1577 =====================
1579 void idAnimBlend::AllowFrameCommands( bool allow ) {
1580 allowFrameCommands = allow;
1585 =====================
1587 =====================
1589 const idAnim *idAnimBlend::Anim( void ) const {
1594 const idAnim *anim = modelDef->GetAnim( animNum );
1599 =====================
1600 idAnimBlend::AnimNum
1601 =====================
1603 int idAnimBlend::AnimNum( void ) const {
1608 =====================
1609 idAnimBlend::AnimTime
1610 =====================
1612 int idAnimBlend::AnimTime( int currentTime ) const {
1615 const idAnim *anim = Anim();
1619 return FRAME2MS( frame - 1 );
1622 // most of the time we're running at the original frame rate, so avoid the int-to-float-to-int conversion
1623 if ( rate == 1.0f ) {
1624 time = currentTime - starttime + timeOffset;
1626 time = static_cast<int>( ( currentTime - starttime ) * rate ) + timeOffset;
1629 // given enough time, we can easily wrap time around in our frame calculations, so
1630 // keep cycling animations' time within the length of the anim.
1631 length = anim->Length();
1632 if ( ( cycle < 0 ) && ( length > 0 ) ) {
1635 // time will wrap after 24 days (oh no!), resulting in negative results for the %.
1636 // adding the length gives us the proper result.
1648 =====================
1649 idAnimBlend::GetFrameNumber
1650 =====================
1652 int idAnimBlend::GetFrameNumber( int currentTime ) const {
1653 const idMD5Anim *md5anim;
1654 frameBlend_t frameinfo;
1657 const idAnim *anim = Anim();
1666 md5anim = anim->MD5Anim( 0 );
1667 animTime = AnimTime( currentTime );
1668 md5anim->ConvertTimeToFrame( animTime, cycle, frameinfo );
1670 return frameinfo.frame1 + 1;
1674 =====================
1675 idAnimBlend::CallFrameCommands
1676 =====================
1678 void idAnimBlend::CallFrameCommands( idEntity *ent, int fromtime, int totime ) const {
1679 const idMD5Anim *md5anim;
1680 frameBlend_t frame1;
1681 frameBlend_t frame2;
1685 if ( !allowFrameCommands || !ent || frame || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
1689 const idAnim *anim = Anim();
1690 if ( !anim || !anim->HasFrameCommands() ) {
1694 if ( totime <= starttime ) {
1695 // don't play until next frame or we'll play commands twice.
1696 // this happens on the player sometimes.
1700 fromFrameTime = AnimTime( fromtime );
1701 toFrameTime = AnimTime( totime );
1702 if ( toFrameTime < fromFrameTime ) {
1703 toFrameTime += anim->Length();
1706 md5anim = anim->MD5Anim( 0 );
1707 md5anim->ConvertTimeToFrame( fromFrameTime, cycle, frame1 );
1708 md5anim->ConvertTimeToFrame( toFrameTime, cycle, frame2 );
1710 if ( fromFrameTime <= 0 ) {
1711 // make sure first frame is called
1712 anim->CallFrameCommands( ent, -1, frame2.frame1 );
1714 anim->CallFrameCommands( ent, frame1.frame1, frame2.frame1 );
1719 =====================
1720 idAnimBlend::BlendAnim
1721 =====================
1723 bool idAnimBlend::BlendAnim( int currentTime, int channel, int numJoints, idJointQuat *blendFrame, float &blendWeight, bool removeOriginOffset, bool overrideBlend, bool printInfo ) const {
1727 const idMD5Anim *md5anim;
1729 frameBlend_t frametime;
1730 idJointQuat *jointFrame;
1731 idJointQuat *mixFrame;
1735 const idAnim *anim = Anim();
1740 float weight = GetWeight( currentTime );
1741 if ( blendWeight > 0.0f ) {
1742 if ( ( endtime >= 0 ) && ( currentTime >= endtime ) ) {
1748 if ( overrideBlend ) {
1749 blendWeight = 1.0f - weight;
1753 if ( ( channel == ANIMCHANNEL_ALL ) && !blendWeight ) {
1754 // we don't need a temporary buffer, so just store it directly in the blend frame
1755 jointFrame = blendFrame;
1757 // allocate a temporary buffer to copy the joints from
1758 jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
1761 time = AnimTime( currentTime );
1763 numAnims = anim->NumAnims();
1764 if ( numAnims == 1 ) {
1765 md5anim = anim->MD5Anim( 0 );
1767 md5anim->GetSingleFrame( frame - 1, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1769 md5anim->ConvertTimeToFrame( time, cycle, frametime );
1770 md5anim->GetInterpolatedFrame( frametime, jointFrame, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1774 // need to mix the multipoint anim together first
1776 // allocate a temporary buffer to copy the joints to
1777 mixFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
1780 anim->MD5Anim( 0 )->ConvertTimeToFrame( time, cycle, frametime );
1785 for( i = 0; i < numAnims; i++ ) {
1786 if ( animWeights[ i ] > 0.0f ) {
1787 mixWeight += animWeights[ i ];
1788 lerp = animWeights[ i ] / mixWeight;
1789 md5anim = anim->MD5Anim( i );
1791 md5anim->GetSingleFrame( frame - 1, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1793 md5anim->GetInterpolatedFrame( frametime, ptr, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1796 // only blend after the first anim is mixed in
1797 if ( ptr != jointFrame ) {
1798 SIMDProcessor->BlendJoints( jointFrame, ptr, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1810 if ( removeOriginOffset ) {
1812 #ifdef VELOCITY_MOVE
1813 jointFrame[ 0 ].t.x = 0.0f;
1815 jointFrame[ 0 ].t.Zero();
1819 if ( anim->GetAnimFlags().anim_turn ) {
1820 jointFrame[ 0 ].q.Set( -0.70710677f, 0.0f, 0.0f, 0.70710677f );
1824 if ( !blendWeight ) {
1825 blendWeight = weight;
1826 if ( channel != ANIMCHANNEL_ALL ) {
1827 const int *index = modelDef->GetChannelJoints( channel );
1828 const int num = modelDef->NumJointsOnChannel( channel );
1829 for( i = 0; i < num; i++ ) {
1831 blendFrame[j].t = jointFrame[j].t;
1832 blendFrame[j].q = jointFrame[j].q;
1836 blendWeight += weight;
1837 lerp = weight / blendWeight;
1838 SIMDProcessor->BlendJoints( blendFrame, jointFrame, lerp, modelDef->GetChannelJoints( channel ), modelDef->NumJointsOnChannel( channel ) );
1843 gameLocal.Printf( " %s: '%s', %d, %.2f%%\n", channelNames[ channel ], anim->FullName(), frame, weight * 100.0f );
1845 gameLocal.Printf( " %s: '%s', %.3f, %.2f%%\n", channelNames[ channel ], anim->FullName(), ( float )frametime.frame1 + frametime.backlerp, weight * 100.0f );
1853 =====================
1854 idAnimBlend::BlendOrigin
1855 =====================
1857 void idAnimBlend::BlendOrigin( int currentTime, idVec3 &blendPos, float &blendWeight, bool removeOriginOffset ) const {
1865 if ( frame || ( ( endtime > 0 ) && ( currentTime > endtime ) ) ) {
1869 const idAnim *anim = Anim();
1874 if ( allowMove && removeOriginOffset ) {
1878 float weight = GetWeight( currentTime );
1883 time = AnimTime( currentTime );
1886 num = anim->NumAnims();
1887 for( i = 0; i < num; i++ ) {
1888 anim->GetOrigin( animpos, i, time, cycle );
1889 pos += animpos * animWeights[ i ];
1892 if ( !blendWeight ) {
1894 blendWeight = weight;
1896 lerp = weight / ( blendWeight + weight );
1897 blendPos += lerp * ( pos - blendPos );
1898 blendWeight += weight;
1903 =====================
1904 idAnimBlend::BlendDelta
1905 =====================
1907 void idAnimBlend::BlendDelta( int fromtime, int totime, idVec3 &blendDelta, float &blendWeight ) const {
1918 if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
1922 const idAnim *anim = Anim();
1927 float weight = GetWeight( totime );
1932 time1 = AnimTime( fromtime );
1933 time2 = AnimTime( totime );
1934 if ( time2 < time1 ) {
1935 time2 += anim->Length();
1938 num = anim->NumAnims();
1942 for( i = 0; i < num; i++ ) {
1943 anim->GetOrigin( animpos, i, time1, cycle );
1944 pos1 += animpos * animWeights[ i ];
1946 anim->GetOrigin( animpos, i, time2, cycle );
1947 pos2 += animpos * animWeights[ i ];
1950 delta = pos2 - pos1;
1951 if ( !blendWeight ) {
1953 blendWeight = weight;
1955 lerp = weight / ( blendWeight + weight );
1956 blendDelta += lerp * ( delta - blendDelta );
1957 blendWeight += weight;
1962 =====================
1963 idAnimBlend::BlendDeltaRotation
1964 =====================
1966 void idAnimBlend::BlendDeltaRotation( int fromtime, int totime, idQuat &blendDelta, float &blendWeight ) const {
1977 if ( frame || !allowMove || ( ( endtime > 0 ) && ( fromtime > endtime ) ) ) {
1981 const idAnim *anim = Anim();
1982 if ( !anim || !anim->GetAnimFlags().anim_turn ) {
1986 float weight = GetWeight( totime );
1991 time1 = AnimTime( fromtime );
1992 time2 = AnimTime( totime );
1993 if ( time2 < time1 ) {
1994 time2 += anim->Length();
1997 q1.Set( 0.0f, 0.0f, 0.0f, 1.0f );
1998 q2.Set( 0.0f, 0.0f, 0.0f, 1.0f );
2001 num = anim->NumAnims();
2002 for( i = 0; i < num; i++ ) {
2003 if ( animWeights[ i ] > 0.0f ) {
2004 mixWeight += animWeights[ i ];
2005 if ( animWeights[ i ] == mixWeight ) {
2006 anim->GetOriginRotation( q1, i, time1, cycle );
2007 anim->GetOriginRotation( q2, i, time2, cycle );
2009 lerp = animWeights[ i ] / mixWeight;
2010 anim->GetOriginRotation( q3, i, time1, cycle );
2011 q1.Slerp( q1, q3, lerp );
2013 anim->GetOriginRotation( q3, i, time2, cycle );
2014 q2.Slerp( q1, q3, lerp );
2019 q3 = q1.Inverse() * q2;
2020 if ( !blendWeight ) {
2022 blendWeight = weight;
2024 lerp = weight / ( blendWeight + weight );
2025 blendDelta.Slerp( blendDelta, q3, lerp );
2026 blendWeight += weight;
2031 =====================
2032 idAnimBlend::AddBounds
2033 =====================
2035 bool idAnimBlend::AddBounds( int currentTime, idBounds &bounds, bool removeOriginOffset ) const {
2043 if ( ( endtime > 0 ) && ( currentTime > endtime ) ) {
2047 const idAnim *anim = Anim();
2052 float weight = GetWeight( currentTime );
2057 time = AnimTime( currentTime );
2058 num = anim->NumAnims();
2060 addorigin = !allowMove || !removeOriginOffset;
2061 for( i = 0; i < num; i++ ) {
2062 if ( anim->GetBounds( b, i, time, cycle ) ) {
2064 anim->GetOrigin( pos, i, time, cycle );
2065 b.TranslateSelf( pos );
2067 bounds.AddBounds( b );
2074 /***********************************************************************
2078 ***********************************************************************/
2081 =====================
2082 idDeclModelDef::idDeclModelDef
2083 =====================
2085 idDeclModelDef::idDeclModelDef() {
2089 for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) {
2090 channelJoints[i].Clear();
2095 =====================
2096 idDeclModelDef::~idDeclModelDef
2097 =====================
2099 idDeclModelDef::~idDeclModelDef() {
2105 idDeclModelDef::Size
2108 size_t idDeclModelDef::Size( void ) const {
2109 return sizeof( idDeclModelDef );
2113 =====================
2114 idDeclModelDef::CopyDecl
2115 =====================
2117 void idDeclModelDef::CopyDecl( const idDeclModelDef *decl ) {
2122 offset = decl->offset;
2123 modelHandle = decl->modelHandle;
2126 anims.SetNum( decl->anims.Num() );
2127 for( i = 0; i < anims.Num(); i++ ) {
2128 anims[ i ] = new idAnim( this, decl->anims[ i ] );
2131 joints.SetNum( decl->joints.Num() );
2132 memcpy( joints.Ptr(), decl->joints.Ptr(), decl->joints.Num() * sizeof( joints[0] ) );
2133 jointParents.SetNum( decl->jointParents.Num() );
2134 memcpy( jointParents.Ptr(), decl->jointParents.Ptr(), decl->jointParents.Num() * sizeof( jointParents[0] ) );
2135 for ( i = 0; i < ANIM_NumAnimChannels; i++ ) {
2136 channelJoints[i] = decl->channelJoints[i];
2141 =====================
2142 idDeclModelDef::FreeData
2143 =====================
2145 void idDeclModelDef::FreeData( void ) {
2146 anims.DeleteContents( true );
2148 jointParents.Clear();
2152 for ( int i = 0; i < ANIM_NumAnimChannels; i++ ) {
2153 channelJoints[i].Clear();
2159 idDeclModelDef::DefaultDefinition
2162 const char *idDeclModelDef::DefaultDefinition( void ) const {
2167 ====================
2168 idDeclModelDef::FindJoint
2169 ====================
2171 const jointInfo_t *idDeclModelDef::FindJoint( const char *name ) const {
2173 const idMD5Joint *joint;
2175 if ( !modelHandle ) {
2179 joint = modelHandle->GetJoints();
2180 for( i = 0; i < joints.Num(); i++, joint++ ) {
2181 if ( !joint->name.Icmp( name ) ) {
2182 return &joints[ i ];
2190 =====================
2191 idDeclModelDef::ModelHandle
2192 =====================
2194 idRenderModel *idDeclModelDef::ModelHandle( void ) const {
2195 return ( idRenderModel * )modelHandle;
2199 =====================
2200 idDeclModelDef::GetJointList
2201 =====================
2203 void idDeclModelDef::GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const {
2206 const jointInfo_t *joint;
2207 const jointInfo_t *child;
2213 if ( !modelHandle ) {
2219 num = modelHandle->NumJoints();
2221 // scan through list of joints and add each to the joint list
2224 // skip over whitespace
2225 while( ( *pos != 0 ) && isspace( *pos ) ) {
2237 if ( *pos == '-' ) {
2244 if ( *pos == '*' ) {
2248 getChildren = false;
2251 while( ( *pos != 0 ) && !isspace( *pos ) ) {
2256 joint = FindJoint( jointname );
2258 gameLocal.Warning( "Unknown joint '%s' in '%s' for model '%s'", jointname.c_str(), jointnames, GetName() );
2263 jointList.AddUnique( joint->num );
2265 jointList.Remove( joint->num );
2268 if ( getChildren ) {
2269 // include all joint's children
2271 for( i = joint->num + 1; i < num; i++, child++ ) {
2272 // all children of the joint should follow it in the list.
2273 // once we reach a joint without a parent or with a parent
2274 // who is earlier in the list than the specified joint, then
2275 // we've gone through all it's children.
2276 if ( child->parentNum < joint->num ) {
2281 jointList.AddUnique( child->num );
2283 jointList.Remove( child->num );
2291 =====================
2292 idDeclModelDef::Touch
2293 =====================
2295 void idDeclModelDef::Touch( void ) const {
2296 if ( modelHandle ) {
2297 renderModelManager->FindModel( modelHandle->Name() );
2302 =====================
2303 idDeclModelDef::GetDefaultSkin
2304 =====================
2306 const idDeclSkin *idDeclModelDef::GetDefaultSkin( void ) const {
2311 =====================
2312 idDeclModelDef::GetDefaultPose
2313 =====================
2315 const idJointQuat *idDeclModelDef::GetDefaultPose( void ) const {
2316 return modelHandle->GetDefaultPose();
2320 =====================
2321 idDeclModelDef::SetupJoints
2322 =====================
2324 void idDeclModelDef::SetupJoints( int *numJoints, idJointMat **jointList, idBounds &frameBounds, bool removeOriginOffset ) const {
2326 const idJointQuat *pose;
2329 if ( !modelHandle || modelHandle->IsDefaultModel() ) {
2330 Mem_Free16( (*jointList) );
2331 (*jointList) = NULL;
2332 frameBounds.Clear();
2336 // get the number of joints
2337 num = modelHandle->NumJoints();
2340 gameLocal.Error( "model '%s' has no joints", modelHandle->Name() );
2343 // set up initial pose for model (with no pose, model is just a jumbled mess)
2344 list = (idJointMat *) Mem_Alloc16( num * sizeof( list[0] ) );
2345 pose = GetDefaultPose();
2347 // convert the joint quaternions to joint matrices
2348 SIMDProcessor->ConvertJointQuatsToJointMats( list, pose, joints.Num() );
2350 // check if we offset the model by the origin joint
2351 if ( removeOriginOffset ) {
2352 #ifdef VELOCITY_MOVE
2353 list[ 0 ].SetTranslation( idVec3( offset.x, offset.y + pose[0].t.y, offset.z + pose[0].t.z ) );
2355 list[ 0 ].SetTranslation( offset );
2358 list[ 0 ].SetTranslation( pose[0].t + offset );
2361 // transform the joint hierarchy
2362 SIMDProcessor->TransformJoints( list, jointParents.Ptr(), 1, joints.Num() - 1 );
2367 // get the bounds of the default pose
2368 frameBounds = modelHandle->Bounds( NULL );
2372 =====================
2373 idDeclModelDef::ParseAnim
2374 =====================
2376 bool idDeclModelDef::ParseAnim( idLexer &src, int numDefaultAnims ) {
2380 const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ];
2381 const idMD5Anim *md5anim;
2389 memset( md5anims, 0, sizeof( md5anims ) );
2391 if( !src.ReadToken( &realname ) ) {
2392 src.Warning( "Unexpected end of file" );
2398 for( i = 0; i < anims.Num(); i++ ) {
2399 if ( !strcmp( anims[ i ]->FullName(), realname ) ) {
2404 if ( ( i < anims.Num() ) && ( i >= numDefaultAnims ) ) {
2405 src.Warning( "Duplicate anim '%s'", realname.c_str() );
2410 if ( i < numDefaultAnims ) {
2413 // create the alias associated with this animation
2414 anim = new idAnim();
2415 anims.Append( anim );
2418 // random anims end with a number. find the numeric suffix of the animation.
2419 len = alias.Length();
2420 for( i = len - 1; i > 0; i-- ) {
2421 if ( !isdigit( alias[ i ] ) ) {
2426 // check for zero length name, or a purely numeric name
2428 src.Warning( "Invalid animation name '%s'", alias.c_str() );
2433 // remove the numeric suffix
2434 alias.CapLength( i + 1 );
2436 // parse the anims from the string
2438 if( !src.ReadToken( &token ) ) {
2439 src.Warning( "Unexpected end of file" );
2444 // lookup the animation
2445 md5anim = animationLib.GetAnim( token );
2447 src.Warning( "Couldn't load anim '%s'", token.c_str() );
2452 md5anim->CheckModelHierarchy( modelHandle );
2454 if ( numAnims > 0 ) {
2455 // make sure it's the same length as the other anims
2456 if ( md5anim->Length() != md5anims[ 0 ]->Length() ) {
2457 src.Warning( "Anim '%s' does not match length of anim '%s'", md5anim->Name(), md5anims[ 0 ]->Name() );
2463 if ( numAnims >= ANIM_MaxSyncedAnims ) {
2464 src.Warning( "Exceeded max synced anims (%d)", ANIM_MaxSyncedAnims );
2469 // add it to our list
2470 md5anims[ numAnims ] = md5anim;
2472 } while ( src.CheckTokenString( "," ) );
2475 src.Warning( "No animation specified" );
2480 anim->SetAnim( this, realname, alias, numAnims, md5anims );
2481 memset( &flags, 0, sizeof( flags ) );
2483 // parse any frame commands or animflags
2484 if ( src.CheckTokenString( "{" ) ) {
2486 if( !src.ReadToken( &token ) ) {
2487 src.Warning( "Unexpected end of file" );
2491 if ( token == "}" ) {
2493 }else if ( token == "prevent_idle_override" ) {
2494 flags.prevent_idle_override = true;
2495 } else if ( token == "random_cycle_start" ) {
2496 flags.random_cycle_start = true;
2497 } else if ( token == "ai_no_turn" ) {
2498 flags.ai_no_turn = true;
2499 } else if ( token == "anim_turn" ) {
2500 flags.anim_turn = true;
2501 } else if ( token == "frame" ) {
2502 // create a frame command
2506 // make sure we don't have any line breaks while reading the frame command so the error line # will be correct
2507 if ( !src.ReadTokenOnLine( &token ) ) {
2508 src.Warning( "Missing frame # after 'frame'" );
2512 if ( token.type == TT_PUNCTUATION && token == "-" ) {
2513 src.Warning( "Invalid frame # after 'frame'" );
2516 } else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
2517 src.Error( "expected integer value, found '%s'", token.c_str() );
2520 // get the frame number
2521 framenum = token.GetIntValue();
2523 // put the command on the specified frame of the animation
2524 err = anim->AddFrameCommand( this, framenum, src, NULL );
2526 src.Warning( "%s", err );
2531 src.Warning( "Unknown command '%s'", token.c_str() );
2539 anim->SetAnimFlags( flags );
2545 idDeclModelDef::Parse
2548 bool idDeclModelDef::Parse( const char *text, const int textLength ) {
2553 const idMD5Joint *md5joint;
2554 const idMD5Joint *md5joints;
2560 jointHandle_t jointnum;
2561 idList<jointHandle_t> jointList;
2562 int numDefaultAnims;
2564 src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
2565 src.SetFlags( DECL_LEXER_FLAGS );
2566 src.SkipUntilString( "{" );
2568 numDefaultAnims = 0;
2570 if ( !src.ReadToken( &token ) ) {
2574 if ( !token.Icmp( "}" ) ) {
2578 if ( token == "inherit" ) {
2579 if( !src.ReadToken( &token2 ) ) {
2580 src.Warning( "Unexpected end of file" );
2585 const idDeclModelDef *copy = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, token2, false ) );
2587 common->Warning( "Unknown model definition '%s'", token2.c_str() );
2588 } else if ( copy->GetState() == DS_DEFAULTED ) {
2589 common->Warning( "inherited model definition '%s' defaulted", token2.c_str() );
2594 numDefaultAnims = anims.Num();
2596 } else if ( token == "skin" ) {
2597 if( !src.ReadToken( &token2 ) ) {
2598 src.Warning( "Unexpected end of file" );
2602 skin = declManager->FindSkin( token2 );
2604 src.Warning( "Skin '%s' not found", token2.c_str() );
2608 } else if ( token == "mesh" ) {
2609 if( !src.ReadToken( &token2 ) ) {
2610 src.Warning( "Unexpected end of file" );
2615 filename.ExtractFileExtension( extension );
2616 if ( extension != MD5_MESH_EXT ) {
2617 src.Warning( "Invalid model for MD5 mesh" );
2621 modelHandle = renderModelManager->FindModel( filename );
2622 if ( !modelHandle ) {
2623 src.Warning( "Model '%s' not found", filename.c_str() );
2628 if ( modelHandle->IsDefaultModel() ) {
2629 src.Warning( "Model '%s' defaulted", filename.c_str() );
2634 // get the number of joints
2635 num = modelHandle->NumJoints();
2637 src.Warning( "Model '%s' has no joints", filename.c_str() );
2640 // set up the joint hierarchy
2641 joints.SetGranularity( 1 );
2642 joints.SetNum( num );
2643 jointParents.SetNum( num );
2644 channelJoints[0].SetNum( num );
2645 md5joints = modelHandle->GetJoints();
2646 md5joint = md5joints;
2647 for( i = 0; i < num; i++, md5joint++ ) {
2648 joints[i].channel = ANIMCHANNEL_ALL;
2649 joints[i].num = static_cast<jointHandle_t>( i );
2650 if ( md5joint->parent ) {
2651 joints[i].parentNum = static_cast<jointHandle_t>( md5joint->parent - md5joints );
2653 joints[i].parentNum = INVALID_JOINT;
2655 jointParents[i] = joints[i].parentNum;
2656 channelJoints[0][i] = i;
2658 } else if ( token == "remove" ) {
2659 // removes any anims whos name matches
2660 if( !src.ReadToken( &token2 ) ) {
2661 src.Warning( "Unexpected end of file" );
2666 for( i = 0; i < anims.Num(); i++ ) {
2667 if ( ( token2 == anims[ i ]->Name() ) || ( token2 == anims[ i ]->FullName() ) ) {
2669 anims.RemoveIndex( i );
2670 if ( i >= numDefaultAnims ) {
2671 src.Warning( "Anim '%s' was not inherited. Anim should be removed from the model def.", token2.c_str() );
2682 src.Warning( "Couldn't find anim '%s' to remove", token2.c_str() );
2686 } else if ( token == "anim" ) {
2687 if ( !modelHandle ) {
2688 src.Warning( "Must specify mesh before defining anims" );
2692 if ( !ParseAnim( src, numDefaultAnims ) ) {
2696 } else if ( token == "offset" ) {
2697 if ( !src.Parse1DMatrix( 3, offset.ToFloatPtr() ) ) {
2698 src.Warning( "Expected vector following 'offset'" );
2702 } else if ( token == "channel" ) {
2703 if ( !modelHandle ) {
2704 src.Warning( "Must specify mesh before defining channels" );
2709 // set the channel for a group of joints
2710 if( !src.ReadToken( &token2 ) ) {
2711 src.Warning( "Unexpected end of file" );
2715 if ( !src.CheckTokenString( "(" ) ) {
2716 src.Warning( "Expected { after '%s'\n", token2.c_str() );
2721 for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) {
2722 if ( !idStr::Icmp( channelNames[ i ], token2 ) ) {
2727 if ( i >= ANIM_NumAnimChannels ) {
2728 src.Warning( "Unknown channel '%s'", token2.c_str() );
2736 while( !src.CheckTokenString( ")" ) ) {
2737 if( !src.ReadToken( &token2 ) ) {
2738 src.Warning( "Unexpected end of file" );
2742 jointnames += token2;
2743 if ( ( token2 != "*" ) && ( token2 != "-" ) ) {
2748 GetJointList( jointnames, jointList );
2750 channelJoints[ channel ].SetNum( jointList.Num() );
2751 for( num = i = 0; i < jointList.Num(); i++ ) {
2752 jointnum = jointList[ i ];
2753 if ( joints[ jointnum ].channel != ANIMCHANNEL_ALL ) {
2754 src.Warning( "Joint '%s' assigned to multiple channels", modelHandle->GetJointName( jointnum ) );
2757 joints[ jointnum ].channel = channel;
2758 channelJoints[ channel ][ num++ ] = jointnum;
2760 channelJoints[ channel ].SetNum( num );
2762 src.Warning( "unknown token '%s'", token.c_str() );
2768 // shrink the anim list down to save space
2769 anims.SetGranularity( 1 );
2770 anims.SetNum( anims.Num() );
2776 =====================
2777 idDeclModelDef::HasAnim
2778 =====================
2780 bool idDeclModelDef::HasAnim( const char *name ) const {
2783 // find any animations with same name
2784 for( i = 0; i < anims.Num(); i++ ) {
2785 if ( !strcmp( anims[ i ]->Name(), name ) ) {
2794 =====================
2795 idDeclModelDef::NumAnims
2796 =====================
2798 int idDeclModelDef::NumAnims( void ) const {
2799 return anims.Num() + 1;
2803 =====================
2804 idDeclModelDef::GetSpecificAnim
2806 Gets the exact anim for the name, without randomization.
2807 =====================
2809 int idDeclModelDef::GetSpecificAnim( const char *name ) const {
2812 // find a specific animation
2813 for( i = 0; i < anims.Num(); i++ ) {
2814 if ( !strcmp( anims[ i ]->FullName(), name ) ) {
2824 =====================
2825 idDeclModelDef::GetAnim
2826 =====================
2828 const idAnim *idDeclModelDef::GetAnim( int index ) const {
2829 if ( ( index < 1 ) || ( index > anims.Num() ) ) {
2833 return anims[ index - 1 ];
2837 =====================
2838 idDeclModelDef::GetAnim
2839 =====================
2841 int idDeclModelDef::GetAnim( const char *name ) const {
2844 const int MAX_ANIMS = 64;
2845 int animList[ MAX_ANIMS ];
2849 len = strlen( name );
2850 if ( len && idStr::CharIsNumeric( name[ len - 1 ] ) ) {
2851 // find a specific animation
2852 return GetSpecificAnim( name );
2855 // find all animations with same name
2857 for( i = 0; i < anims.Num(); i++ ) {
2858 if ( !strcmp( anims[ i ]->Name(), name ) ) {
2859 animList[ numAnims++ ] = i;
2860 if ( numAnims >= MAX_ANIMS ) {
2870 // get a random anim
2871 //FIXME: don't access gameLocal here?
2872 which = gameLocal.random.RandomInt( numAnims );
2873 return animList[ which ] + 1;
2877 =====================
2878 idDeclModelDef::GetSkin
2879 =====================
2881 const idDeclSkin *idDeclModelDef::GetSkin( void ) const {
2886 =====================
2887 idDeclModelDef::GetModelName
2888 =====================
2890 const char *idDeclModelDef::GetModelName( void ) const {
2891 if ( modelHandle ) {
2892 return modelHandle->Name();
2899 =====================
2900 idDeclModelDef::Joints
2901 =====================
2903 const idList<jointInfo_t> &idDeclModelDef::Joints( void ) const {
2908 =====================
2909 idDeclModelDef::JointParents
2910 =====================
2912 const int * idDeclModelDef::JointParents( void ) const {
2913 return jointParents.Ptr();
2917 =====================
2918 idDeclModelDef::NumJoints
2919 =====================
2921 int idDeclModelDef::NumJoints( void ) const {
2922 return joints.Num();
2926 =====================
2927 idDeclModelDef::GetJoint
2928 =====================
2930 const jointInfo_t *idDeclModelDef::GetJoint( int jointHandle ) const {
2931 if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) {
2932 gameLocal.Error( "idDeclModelDef::GetJoint : joint handle out of range" );
2934 return &joints[ jointHandle ];
2938 ====================
2939 idDeclModelDef::GetJointName
2940 ====================
2942 const char *idDeclModelDef::GetJointName( int jointHandle ) const {
2943 const idMD5Joint *joint;
2945 if ( !modelHandle ) {
2949 if ( ( jointHandle < 0 ) || ( jointHandle > joints.Num() ) ) {
2950 gameLocal.Error( "idDeclModelDef::GetJointName : joint handle out of range" );
2953 joint = modelHandle->GetJoints();
2954 return joint[ jointHandle ].name.c_str();
2958 =====================
2959 idDeclModelDef::NumJointsOnChannel
2960 =====================
2962 int idDeclModelDef::NumJointsOnChannel( int channel ) const {
2963 if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) {
2964 gameLocal.Error( "idDeclModelDef::NumJointsOnChannel : channel out of range" );
2966 return channelJoints[ channel ].Num();
2970 =====================
2971 idDeclModelDef::GetChannelJoints
2972 =====================
2974 const int * idDeclModelDef::GetChannelJoints( int channel ) const {
2975 if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) {
2976 gameLocal.Error( "idDeclModelDef::GetChannelJoints : channel out of range" );
2978 return channelJoints[ channel ].Ptr();
2982 =====================
2983 idDeclModelDef::GetVisualOffset
2984 =====================
2986 const idVec3 &idDeclModelDef::GetVisualOffset( void ) const {
2990 /***********************************************************************
2994 ***********************************************************************/
2997 =====================
2998 idAnimator::idAnimator
2999 =====================
3001 idAnimator::idAnimator() {
3008 lastTransformTime = -1;
3009 stoppedAnimatingUpdate = false;
3010 removeOriginOffset = false;
3011 forceUpdate = false;
3013 frameBounds.Clear();
3015 AFPoseJoints.SetGranularity( 1 );
3016 AFPoseJointMods.SetGranularity( 1 );
3017 AFPoseJointFrame.SetGranularity( 1 );
3021 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3022 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3023 channels[ i ][ j ].Reset( NULL );
3029 =====================
3030 idAnimator::~idAnimator
3031 =====================
3033 idAnimator::~idAnimator() {
3038 =====================
3039 idAnimator::Allocated
3040 =====================
3042 size_t idAnimator::Allocated( void ) const {
3045 size = jointMods.Allocated() + numJoints * sizeof( joints[0] ) + jointMods.Num() * sizeof( jointMods[ 0 ] ) + AFPoseJointMods.Allocated() + AFPoseJointFrame.Allocated() + AFPoseJoints.Allocated();
3051 =====================
3054 archives object for save game file
3055 =====================
3057 void idAnimator::Save( idSaveGame *savefile ) const {
3061 savefile->WriteModelDef( modelDef );
3062 savefile->WriteObject( entity );
3064 savefile->WriteInt( jointMods.Num() );
3065 for( i = 0; i < jointMods.Num(); i++ ) {
3066 savefile->WriteInt( jointMods[ i ]->jointnum );
3067 savefile->WriteMat3( jointMods[ i ]->mat );
3068 savefile->WriteVec3( jointMods[ i ]->pos );
3069 savefile->WriteInt( (int&)jointMods[ i ]->transform_pos );
3070 savefile->WriteInt( (int&)jointMods[ i ]->transform_axis );
3073 savefile->WriteInt( numJoints );
3074 for ( i = 0; i < numJoints; i++ ) {
3075 float *data = joints[i].ToFloatPtr();
3076 for ( j = 0; j < 12; j++ ) {
3077 savefile->WriteFloat( data[j] );
3081 savefile->WriteInt( lastTransformTime );
3082 savefile->WriteBool( stoppedAnimatingUpdate );
3083 savefile->WriteBool( forceUpdate );
3084 savefile->WriteBounds( frameBounds );
3086 savefile->WriteFloat( AFPoseBlendWeight );
3088 savefile->WriteInt( AFPoseJoints.Num() );
3089 for ( i = 0; i < AFPoseJoints.Num(); i++ ) {
3090 savefile->WriteInt( AFPoseJoints[i] );
3093 savefile->WriteInt( AFPoseJointMods.Num() );
3094 for ( i = 0; i < AFPoseJointMods.Num(); i++ ) {
3095 savefile->WriteInt( (int&)AFPoseJointMods[i].mod );
3096 savefile->WriteMat3( AFPoseJointMods[i].axis );
3097 savefile->WriteVec3( AFPoseJointMods[i].origin );
3100 savefile->WriteInt( AFPoseJointFrame.Num() );
3101 for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) {
3102 savefile->WriteFloat( AFPoseJointFrame[i].q.x );
3103 savefile->WriteFloat( AFPoseJointFrame[i].q.y );
3104 savefile->WriteFloat( AFPoseJointFrame[i].q.z );
3105 savefile->WriteFloat( AFPoseJointFrame[i].q.w );
3106 savefile->WriteVec3( AFPoseJointFrame[i].t );
3109 savefile->WriteBounds( AFPoseBounds );
3110 savefile->WriteInt( AFPoseTime );
3112 savefile->WriteBool( removeOriginOffset );
3114 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3115 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3116 channels[ i ][ j ].Save( savefile );
3122 =====================
3125 unarchives object from save game file
3126 =====================
3128 void idAnimator::Restore( idRestoreGame *savefile ) {
3133 savefile->ReadModelDef( modelDef );
3134 savefile->ReadObject( reinterpret_cast<idClass *&>( entity ) );
3136 savefile->ReadInt( num );
3137 jointMods.SetNum( num );
3138 for( i = 0; i < num; i++ ) {
3139 jointMods[ i ] = new jointMod_t;
3140 savefile->ReadInt( (int&)jointMods[ i ]->jointnum );
3141 savefile->ReadMat3( jointMods[ i ]->mat );
3142 savefile->ReadVec3( jointMods[ i ]->pos );
3143 savefile->ReadInt( (int&)jointMods[ i ]->transform_pos );
3144 savefile->ReadInt( (int&)jointMods[ i ]->transform_axis );
3147 savefile->ReadInt( numJoints );
3148 joints = (idJointMat *) Mem_Alloc16( numJoints * sizeof( joints[0] ) );
3149 for ( i = 0; i < numJoints; i++ ) {
3150 float *data = joints[i].ToFloatPtr();
3151 for ( j = 0; j < 12; j++ ) {
3152 savefile->ReadFloat( data[j] );
3156 savefile->ReadInt( lastTransformTime );
3157 savefile->ReadBool( stoppedAnimatingUpdate );
3158 savefile->ReadBool( forceUpdate );
3159 savefile->ReadBounds( frameBounds );
3161 savefile->ReadFloat( AFPoseBlendWeight );
3163 savefile->ReadInt( num );
3164 AFPoseJoints.SetGranularity( 1 );
3165 AFPoseJoints.SetNum( num );
3166 for ( i = 0; i < AFPoseJoints.Num(); i++ ) {
3167 savefile->ReadInt( AFPoseJoints[i] );
3170 savefile->ReadInt( num );
3171 AFPoseJointMods.SetGranularity( 1 );
3172 AFPoseJointMods.SetNum( num );
3173 for ( i = 0; i < AFPoseJointMods.Num(); i++ ) {
3174 savefile->ReadInt( (int&)AFPoseJointMods[i].mod );
3175 savefile->ReadMat3( AFPoseJointMods[i].axis );
3176 savefile->ReadVec3( AFPoseJointMods[i].origin );
3179 savefile->ReadInt( num );
3180 AFPoseJointFrame.SetGranularity( 1 );
3181 AFPoseJointFrame.SetNum( num );
3182 for ( i = 0; i < AFPoseJointFrame.Num(); i++ ) {
3183 savefile->ReadFloat( AFPoseJointFrame[i].q.x );
3184 savefile->ReadFloat( AFPoseJointFrame[i].q.y );
3185 savefile->ReadFloat( AFPoseJointFrame[i].q.z );
3186 savefile->ReadFloat( AFPoseJointFrame[i].q.w );
3187 savefile->ReadVec3( AFPoseJointFrame[i].t );
3190 savefile->ReadBounds( AFPoseBounds );
3191 savefile->ReadInt( AFPoseTime );
3193 savefile->ReadBool( removeOriginOffset );
3195 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3196 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3197 channels[ i ][ j ].Restore( savefile, modelDef );
3203 =====================
3204 idAnimator::FreeData
3205 =====================
3207 void idAnimator::FreeData( void ) {
3211 entity->BecomeInactive( TH_ANIMATE );
3214 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3215 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3216 channels[ i ][ j ].Reset( NULL );
3220 jointMods.DeleteContents( true );
3222 Mem_Free16( joints );
3232 =====================
3233 idAnimator::PushAnims
3234 =====================
3236 void idAnimator::PushAnims( int channelNum, int currentTime, int blendTime ) {
3238 idAnimBlend *channel;
3240 channel = channels[ channelNum ];
3241 if ( !channel[ 0 ].GetWeight( currentTime ) || ( channel[ 0 ].starttime == currentTime ) ) {
3245 for( i = ANIM_MaxAnimsPerChannel - 1; i > 0; i-- ) {
3246 channel[ i ] = channel[ i - 1 ];
3249 channel[ 0 ].Reset( modelDef );
3250 channel[ 1 ].Clear( currentTime, blendTime );
3255 =====================
3256 idAnimator::SetModel
3257 =====================
3259 idRenderModel *idAnimator::SetModel( const char *modelname ) {
3264 // check if we're just clearing the model
3265 if ( !modelname || !*modelname ) {
3269 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
3274 idRenderModel *renderModel = modelDef->ModelHandle();
3275 if ( !renderModel ) {
3280 // make sure model hasn't been purged
3283 modelDef->SetupJoints( &numJoints, &joints, frameBounds, removeOriginOffset );
3284 modelDef->ModelHandle()->Reset();
3286 // set the modelDef on all channels
3287 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3288 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++ ) {
3289 channels[ i ][ j ].Reset( modelDef );
3293 return modelDef->ModelHandle();
3297 =====================
3299 =====================
3301 size_t idAnimator::Size( void ) const {
3302 return sizeof( *this ) + Allocated();
3306 =====================
3307 idAnimator::SetEntity
3308 =====================
3310 void idAnimator::SetEntity( idEntity *ent ) {
3315 =====================
3316 idAnimator::GetEntity
3317 =====================
3319 idEntity *idAnimator::GetEntity( void ) const {
3324 =====================
3325 idAnimator::RemoveOriginOffset
3326 =====================
3328 void idAnimator::RemoveOriginOffset( bool remove ) {
3329 removeOriginOffset = remove;
3333 =====================
3334 idAnimator::RemoveOrigin
3335 =====================
3337 bool idAnimator::RemoveOrigin( void ) const {
3338 return removeOriginOffset;
3342 =====================
3343 idAnimator::GetJointList
3344 =====================
3346 void idAnimator::GetJointList( const char *jointnames, idList<jointHandle_t> &jointList ) const {
3348 modelDef->GetJointList( jointnames, jointList );
3353 =====================
3354 idAnimator::NumAnims
3355 =====================
3357 int idAnimator::NumAnims( void ) const {
3362 return modelDef->NumAnims();
3366 =====================
3368 =====================
3370 const idAnim *idAnimator::GetAnim( int index ) const {
3375 return modelDef->GetAnim( index );
3379 =====================
3381 =====================
3383 int idAnimator::GetAnim( const char *name ) const {
3388 return modelDef->GetAnim( name );
3392 =====================
3394 =====================
3396 bool idAnimator::HasAnim( const char *name ) const {
3401 return modelDef->HasAnim( name );
3405 =====================
3406 idAnimator::NumJoints
3407 =====================
3409 int idAnimator::NumJoints( void ) const {
3414 =====================
3415 idAnimator::ModelHandle
3416 =====================
3418 idRenderModel *idAnimator::ModelHandle( void ) const {
3423 return modelDef->ModelHandle();
3427 =====================
3428 idAnimator::ModelDef
3429 =====================
3431 const idDeclModelDef *idAnimator::ModelDef( void ) const {
3436 =====================
3437 idAnimator::CurrentAnim
3438 =====================
3440 idAnimBlend *idAnimator::CurrentAnim( int channelNum ) {
3441 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3442 gameLocal.Error( "idAnimator::CurrentAnim : channel out of range" );
3445 return &channels[ channelNum ][ 0 ];
3449 =====================
3451 =====================
3453 void idAnimator::Clear( int channelNum, int currentTime, int cleartime ) {
3457 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3458 gameLocal.Error( "idAnimator::Clear : channel out of range" );
3461 blend = channels[ channelNum ];
3462 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3463 blend->Clear( currentTime, cleartime );
3469 =====================
3470 idAnimator::SetFrame
3471 =====================
3473 void idAnimator::SetFrame( int channelNum, int animNum, int frame, int currentTime, int blendTime ) {
3474 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3475 gameLocal.Error( "idAnimator::SetFrame : channel out of range" );
3478 if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3482 PushAnims( channelNum, currentTime, blendTime );
3483 channels[ channelNum ][ 0 ].SetFrame( modelDef, animNum, frame, currentTime, blendTime );
3485 entity->BecomeActive( TH_ANIMATE );
3490 =====================
3491 idAnimator::CycleAnim
3492 =====================
3494 void idAnimator::CycleAnim( int channelNum, int animNum, int currentTime, int blendTime ) {
3495 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3496 gameLocal.Error( "idAnimator::CycleAnim : channel out of range" );
3499 if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3503 PushAnims( channelNum, currentTime, blendTime );
3504 channels[ channelNum ][ 0 ].CycleAnim( modelDef, animNum, currentTime, blendTime );
3506 entity->BecomeActive( TH_ANIMATE );
3511 =====================
3512 idAnimator::PlayAnim
3513 =====================
3515 void idAnimator::PlayAnim( int channelNum, int animNum, int currentTime, int blendTime ) {
3516 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) ) {
3517 gameLocal.Error( "idAnimator::PlayAnim : channel out of range" );
3520 if ( !modelDef || !modelDef->GetAnim( animNum ) ) {
3524 PushAnims( channelNum, currentTime, blendTime );
3525 channels[ channelNum ][ 0 ].PlayAnim( modelDef, animNum, currentTime, blendTime );
3527 entity->BecomeActive( TH_ANIMATE );
3532 =====================
3533 idAnimator::SyncAnimChannels
3534 =====================
3536 void idAnimator::SyncAnimChannels( int channelNum, int fromChannelNum, int currentTime, int blendTime ) {
3537 if ( ( channelNum < 0 ) || ( channelNum >= ANIM_NumAnimChannels ) || ( fromChannelNum < 0 ) || ( fromChannelNum >= ANIM_NumAnimChannels ) ) {
3538 gameLocal.Error( "idAnimator::SyncToChannel : channel out of range" );
3541 idAnimBlend &fromBlend = channels[ fromChannelNum ][ 0 ];
3542 idAnimBlend &toBlend = channels[ channelNum ][ 0 ];
3544 float weight = fromBlend.blendEndValue;
3545 if ( ( fromBlend.Anim() != toBlend.Anim() ) || ( fromBlend.GetStartTime() != toBlend.GetStartTime() ) || ( fromBlend.GetEndTime() != toBlend.GetEndTime() ) ) {
3546 PushAnims( channelNum, currentTime, blendTime );
3547 toBlend = fromBlend;
3548 toBlend.blendStartValue = 0.0f;
3549 toBlend.blendEndValue = 0.0f;
3551 toBlend.SetWeight( weight, currentTime - 1, blendTime );
3553 // disable framecommands on the current channel so that commands aren't called twice
3554 toBlend.AllowFrameCommands( false );
3557 entity->BecomeActive( TH_ANIMATE );
3562 =====================
3563 idAnimator::SetJointPos
3564 =====================
3566 void idAnimator::SetJointPos( jointHandle_t jointnum, jointModTransform_t transform_type, const idVec3 &pos ) {
3568 jointMod_t *jointMod;
3570 if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3575 for( i = 0; i < jointMods.Num(); i++ ) {
3576 if ( jointMods[ i ]->jointnum == jointnum ) {
3577 jointMod = jointMods[ i ];
3579 } else if ( jointMods[ i ]->jointnum > jointnum ) {
3585 jointMod = new jointMod_t;
3586 jointMod->jointnum = jointnum;
3587 jointMod->mat.Identity();
3588 jointMod->transform_axis = JOINTMOD_NONE;
3589 jointMods.Insert( jointMod, i );
3592 jointMod->pos = pos;
3593 jointMod->transform_pos = transform_type;
3596 entity->BecomeActive( TH_ANIMATE );
3602 =====================
3603 idAnimator::SetJointAxis
3604 =====================
3606 void idAnimator::SetJointAxis( jointHandle_t jointnum, jointModTransform_t transform_type, const idMat3 &mat ) {
3608 jointMod_t *jointMod;
3610 if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3615 for( i = 0; i < jointMods.Num(); i++ ) {
3616 if ( jointMods[ i ]->jointnum == jointnum ) {
3617 jointMod = jointMods[ i ];
3619 } else if ( jointMods[ i ]->jointnum > jointnum ) {
3625 jointMod = new jointMod_t;
3626 jointMod->jointnum = jointnum;
3627 jointMod->pos.Zero();
3628 jointMod->transform_pos = JOINTMOD_NONE;
3629 jointMods.Insert( jointMod, i );
3632 jointMod->mat = mat;
3633 jointMod->transform_axis = transform_type;
3636 entity->BecomeActive( TH_ANIMATE );
3642 =====================
3643 idAnimator::ClearJoint
3644 =====================
3646 void idAnimator::ClearJoint( jointHandle_t jointnum ) {
3649 if ( !modelDef || !modelDef->ModelHandle() || ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
3653 for( i = 0; i < jointMods.Num(); i++ ) {
3654 if ( jointMods[ i ]->jointnum == jointnum ) {
3655 delete jointMods[ i ];
3656 jointMods.RemoveIndex( i );
3659 } else if ( jointMods[ i ]->jointnum > jointnum ) {
3666 =====================
3667 idAnimator::ClearAllJoints
3668 =====================
3670 void idAnimator::ClearAllJoints( void ) {
3671 if ( jointMods.Num() ) {
3674 jointMods.DeleteContents( true );
3678 =====================
3679 idAnimator::ClearAllAnims
3680 =====================
3682 void idAnimator::ClearAllAnims( int currentTime, int cleartime ) {
3685 for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
3686 Clear( i, currentTime, cleartime );
3694 ====================
3695 idAnimator::GetDelta
3696 ====================
3698 void idAnimator::GetDelta( int fromtime, int totime, idVec3 &delta ) const {
3700 const idAnimBlend *blend;
3703 if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) {
3711 blend = channels[ ANIMCHANNEL_ALL ];
3712 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3713 blend->BlendDelta( fromtime, totime, delta, blendWeight );
3716 if ( modelDef->Joints()[ 0 ].channel ) {
3717 blend = channels[ modelDef->Joints()[ 0 ].channel ];
3718 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3719 blend->BlendDelta( fromtime, totime, delta, blendWeight );
3725 ====================
3726 idAnimator::GetDeltaRotation
3727 ====================
3729 bool idAnimator::GetDeltaRotation( int fromtime, int totime, idMat3 &delta ) const {
3731 const idAnimBlend *blend;
3735 if ( !modelDef || !modelDef->ModelHandle() || ( fromtime == totime ) ) {
3740 q.Set( 0.0f, 0.0f, 0.0f, 1.0f );
3743 blend = channels[ ANIMCHANNEL_ALL ];
3744 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3745 blend->BlendDeltaRotation( fromtime, totime, q, blendWeight );
3748 if ( modelDef->Joints()[ 0 ].channel ) {
3749 blend = channels[ modelDef->Joints()[ 0 ].channel ];
3750 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3751 blend->BlendDeltaRotation( fromtime, totime, q, blendWeight );
3755 if ( blendWeight > 0.0f ) {
3765 ====================
3766 idAnimator::GetOrigin
3767 ====================
3769 void idAnimator::GetOrigin( int currentTime, idVec3 &pos ) const {
3771 const idAnimBlend *blend;
3774 if ( !modelDef || !modelDef->ModelHandle() ) {
3782 blend = channels[ ANIMCHANNEL_ALL ];
3783 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3784 blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset );
3787 if ( modelDef->Joints()[ 0 ].channel ) {
3788 blend = channels[ modelDef->Joints()[ 0 ].channel ];
3789 for( i = 0; i < ANIM_MaxAnimsPerChannel; i++, blend++ ) {
3790 blend->BlendOrigin( currentTime, pos, blendWeight, removeOriginOffset );
3794 pos += modelDef->GetVisualOffset();
3798 ====================
3799 idAnimator::GetBounds
3800 ====================
3802 bool idAnimator::GetBounds( int currentTime, idBounds &bounds ) {
3804 const idAnimBlend *blend;
3807 if ( !modelDef || !modelDef->ModelHandle() ) {
3811 if ( AFPoseJoints.Num() ) {
3812 bounds = AFPoseBounds;
3819 blend = channels[ 0 ];
3820 for( i = ANIMCHANNEL_ALL; i < ANIM_NumAnimChannels; i++ ) {
3821 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
3822 if ( blend->AddBounds( currentTime, bounds, removeOriginOffset ) ) {
3829 if ( !frameBounds.IsCleared() ) {
3830 bounds = frameBounds;
3838 bounds.TranslateSelf( modelDef->GetVisualOffset() );
3840 if ( g_debugBounds.GetBool() ) {
3841 if ( bounds[1][0] - bounds[0][0] > 2048 || bounds[1][1] - bounds[0][1] > 2048 ) {
3843 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] );
3845 gameLocal.Warning( "big frameBounds on model '%s': %f,%f", modelDef->ModelHandle()->Name(), bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1] );
3850 frameBounds = bounds;
3856 =====================
3857 idAnimator::InitAFPose
3858 =====================
3860 void idAnimator::InitAFPose( void ) {
3866 AFPoseJoints.SetNum( modelDef->Joints().Num(), false );
3867 AFPoseJoints.SetNum( 0, false );
3868 AFPoseJointMods.SetNum( modelDef->Joints().Num(), false );
3869 AFPoseJointFrame.SetNum( modelDef->Joints().Num(), false );
3873 =====================
3874 idAnimator::SetAFPoseJointMod
3875 =====================
3877 void idAnimator::SetAFPoseJointMod( const jointHandle_t jointNum, const AFJointModType_t mod, const idMat3 &axis, const idVec3 &origin ) {
3878 AFPoseJointMods[jointNum].mod = mod;
3879 AFPoseJointMods[jointNum].axis = axis;
3880 AFPoseJointMods[jointNum].origin = origin;
3882 int index = idBinSearch_GreaterEqual<int>( AFPoseJoints.Ptr(), AFPoseJoints.Num(), jointNum );
3883 if ( index >= AFPoseJoints.Num() || jointNum != AFPoseJoints[index] ) {
3884 AFPoseJoints.Insert( jointNum, index );
3889 =====================
3890 idAnimator::FinishAFPose
3891 =====================
3893 void idAnimator::FinishAFPose( int animNum, const idBounds &bounds, const int time ) {
3899 const int * jointParent;
3905 const idAnim *anim = modelDef->GetAnim( animNum );
3910 numJoints = modelDef->Joints().Num();
3915 idRenderModel *md5 = modelDef->ModelHandle();
3916 const idMD5Anim *md5anim = anim->MD5Anim( 0 );
3918 if ( numJoints != md5anim->NumJoints() ) {
3919 gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", md5->Name(), md5anim->Name() );
3923 idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
3924 md5anim->GetSingleFrame( 0, jointFrame, modelDef->GetChannelJoints( ANIMCHANNEL_ALL ), modelDef->NumJointsOnChannel( ANIMCHANNEL_ALL ) );
3926 if ( removeOriginOffset ) {
3927 #ifdef VELOCITY_MOVE
3928 jointFrame[ 0 ].t.x = 0.0f;
3930 jointFrame[ 0 ].t.Zero();
3934 idJointMat *joints = ( idJointMat * )_alloca16( numJoints * sizeof( *joints ) );
3936 // convert the joint quaternions to joint matrices
3937 SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
3939 // first joint is always root of entire hierarchy
3940 if ( AFPoseJoints.Num() && AFPoseJoints[0] == 0 ) {
3941 switch( AFPoseJointMods[0].mod ) {
3942 case AF_JOINTMOD_AXIS: {
3943 joints[0].SetRotation( AFPoseJointMods[0].axis );
3946 case AF_JOINTMOD_ORIGIN: {
3947 joints[0].SetTranslation( AFPoseJointMods[0].origin );
3950 case AF_JOINTMOD_BOTH: {
3951 joints[0].SetRotation( AFPoseJointMods[0].axis );
3952 joints[0].SetTranslation( AFPoseJointMods[0].origin );
3961 // pointer to joint info
3962 jointParent = modelDef->JointParents();
3964 // transform the child joints
3965 for( i = 1; j < AFPoseJoints.Num(); j++, i++ ) {
3966 jointMod = AFPoseJoints[j];
3968 // transform any joints preceding the joint modifier
3969 SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod - 1 );
3972 parentNum = jointParent[i];
3974 switch( AFPoseJointMods[jointMod].mod ) {
3975 case AF_JOINTMOD_AXIS: {
3976 joints[i].SetRotation( AFPoseJointMods[jointMod].axis );
3977 joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() );
3980 case AF_JOINTMOD_ORIGIN: {
3981 joints[i].SetRotation( joints[i].ToMat3() * joints[parentNum].ToMat3() );
3982 joints[i].SetTranslation( AFPoseJointMods[jointMod].origin );
3985 case AF_JOINTMOD_BOTH: {
3986 joints[i].SetRotation( AFPoseJointMods[jointMod].axis );
3987 joints[i].SetTranslation( AFPoseJointMods[jointMod].origin );
3993 // transform the rest of the hierarchy
3994 SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 );
3996 // untransform hierarchy
3997 SIMDProcessor->UntransformJoints( joints, jointParent, 1, numJoints - 1 );
3999 // convert joint matrices back to joint quaternions
4000 SIMDProcessor->ConvertJointMatsToJointQuats( AFPoseJointFrame.Ptr(), joints, numJoints );
4002 // find all modified joints and their parents
4003 bool *blendJoints = (bool *) _alloca16( numJoints * sizeof( bool ) );
4004 memset( blendJoints, 0, numJoints * sizeof( bool ) );
4006 // mark all modified joints and their parents
4007 for( i = 0; i < AFPoseJoints.Num(); i++ ) {
4008 for( jointNum = AFPoseJoints[i]; jointNum != INVALID_JOINT; jointNum = jointParent[jointNum] ) {
4009 blendJoints[jointNum] = true;
4013 // lock all parents of modified joints
4014 AFPoseJoints.SetNum( 0, false );
4015 for ( i = 0; i < numJoints; i++ ) {
4016 if ( blendJoints[i] ) {
4017 AFPoseJoints.Append( i );
4021 AFPoseBounds = bounds;
4028 =====================
4029 idAnimator::SetAFPoseBlendWeight
4030 =====================
4032 void idAnimator::SetAFPoseBlendWeight( float blendWeight ) {
4033 AFPoseBlendWeight = blendWeight;
4037 =====================
4038 idAnimator::BlendAFPose
4039 =====================
4041 bool idAnimator::BlendAFPose( idJointQuat *blendFrame ) const {
4043 if ( !AFPoseJoints.Num() ) {
4047 SIMDProcessor->BlendJoints( blendFrame, AFPoseJointFrame.Ptr(), AFPoseBlendWeight, AFPoseJoints.Ptr(), AFPoseJoints.Num() );
4053 =====================
4054 idAnimator::ClearAFPose
4055 =====================
4057 void idAnimator::ClearAFPose( void ) {
4058 if ( AFPoseJoints.Num() ) {
4061 AFPoseBlendWeight = 1.0f;
4062 AFPoseJoints.SetNum( 0, false );
4063 AFPoseBounds.Clear();
4068 =====================
4069 idAnimator::ServiceAnims
4070 =====================
4072 void idAnimator::ServiceAnims( int fromtime, int totime ) {
4080 if ( modelDef->ModelHandle() ) {
4081 blend = channels[ 0 ];
4082 for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4083 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4084 blend->CallFrameCommands( entity, fromtime, totime );
4089 if ( !IsAnimating( totime ) ) {
4090 stoppedAnimatingUpdate = true;
4092 entity->BecomeInactive( TH_ANIMATE );
4094 // present one more time with stopped animations so the renderer can properly recreate interactions
4095 entity->BecomeActive( TH_UPDATEVISUALS );
4101 =====================
4102 idAnimator::IsAnimating
4103 =====================
4105 bool idAnimator::IsAnimating( int currentTime ) const {
4107 const idAnimBlend *blend;
4109 if ( !modelDef || !modelDef->ModelHandle() ) {
4113 // if animating with an articulated figure
4114 if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) {
4118 blend = channels[ 0 ];
4119 for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4120 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4121 if ( !blend->IsDone( currentTime ) ) {
4131 =====================
4132 idAnimator::FrameHasChanged
4133 =====================
4135 bool idAnimator::FrameHasChanged( int currentTime ) const {
4137 const idAnimBlend *blend;
4139 if ( !modelDef || !modelDef->ModelHandle() ) {
4143 // if animating with an articulated figure
4144 if ( AFPoseJoints.Num() && currentTime <= AFPoseTime ) {
4148 blend = channels[ 0 ];
4149 for( i = 0; i < ANIM_NumAnimChannels; i++ ) {
4150 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4151 if ( blend->FrameHasChanged( currentTime ) ) {
4157 if ( forceUpdate && IsAnimating( currentTime ) ) {
4165 =====================
4166 idAnimator::CreateFrame
4167 =====================
4169 bool idAnimator::CreateFrame( int currentTime, bool force ) {
4177 const idAnimBlend * blend;
4178 const int * jointParent;
4179 const jointMod_t * jointMod;
4180 const idJointQuat * defaultPose;
4182 static idCVar r_showSkel( "r_showSkel", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
4184 if ( gameLocal.inCinematic && gameLocal.skipCinematic ) {
4188 if ( !modelDef || !modelDef->ModelHandle() ) {
4192 if ( !force && !r_showSkel.GetInteger() ) {
4193 if ( lastTransformTime == currentTime ) {
4196 if ( lastTransformTime != -1 && !stoppedAnimatingUpdate && !IsAnimating( currentTime ) ) {
4201 lastTransformTime = currentTime;
4202 stoppedAnimatingUpdate = false;
4204 if ( entity && ( ( g_debugAnim.GetInteger() == entity->entityNumber ) || ( g_debugAnim.GetInteger() == -2 ) ) ) {
4206 gameLocal.Printf( "---------------\n%d: entity '%s':\n", gameLocal.time, entity->GetName() );
4207 gameLocal.Printf( "model '%s':\n", modelDef->GetModelName() );
4212 // init the joint buffer
4213 if ( AFPoseJoints.Num() ) {
4214 // initialize with AF pose anim for the case where there are no other animations and no AF pose joint modifications
4215 defaultPose = AFPoseJointFrame.Ptr();
4217 defaultPose = modelDef->GetDefaultPose();
4220 if ( !defaultPose ) {
4221 //gameLocal.Warning( "idAnimator::CreateFrame: no defaultPose on '%s'", modelDef->Name() );
4225 numJoints = modelDef->Joints().Num();
4226 idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( jointFrame[0] ) );
4227 SIMDProcessor->Memcpy( jointFrame, defaultPose, numJoints * sizeof( jointFrame[0] ) );
4231 // blend the all channel
4233 blend = channels[ ANIMCHANNEL_ALL ];
4234 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4235 if ( blend->BlendAnim( currentTime, ANIMCHANNEL_ALL, numJoints, jointFrame, baseBlend, removeOriginOffset, false, debugInfo ) ) {
4237 if ( baseBlend >= 1.0f ) {
4243 // only blend other channels if there's enough space to blend into
4244 if ( baseBlend < 1.0f ) {
4245 for( i = ANIMCHANNEL_ALL + 1; i < ANIM_NumAnimChannels; i++ ) {
4246 if ( !modelDef->NumJointsOnChannel( i ) ) {
4249 if ( i == ANIMCHANNEL_EYELIDS ) {
4250 // eyelids blend over any previous anims, so skip it and blend it later
4253 blendWeight = baseBlend;
4254 blend = channels[ i ];
4255 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4256 if ( blend->BlendAnim( currentTime, i, numJoints, jointFrame, blendWeight, removeOriginOffset, false, debugInfo ) ) {
4258 if ( blendWeight >= 1.0f ) {
4265 if ( debugInfo && !AFPoseJoints.Num() && !blendWeight ) {
4266 gameLocal.Printf( "%d: %s using default pose in model '%s'\n", gameLocal.time, channelNames[ i ], modelDef->GetModelName() );
4271 // blend in the eyelids
4272 if ( modelDef->NumJointsOnChannel( ANIMCHANNEL_EYELIDS ) ) {
4273 blend = channels[ ANIMCHANNEL_EYELIDS ];
4274 blendWeight = baseBlend;
4275 for( j = 0; j < ANIM_MaxAnimsPerChannel; j++, blend++ ) {
4276 if ( blend->BlendAnim( currentTime, ANIMCHANNEL_EYELIDS, numJoints, jointFrame, blendWeight, removeOriginOffset, true, debugInfo ) ) {
4278 if ( blendWeight >= 1.0f ) {
4286 // blend the articulated figure pose
4287 if ( BlendAFPose( jointFrame ) ) {
4291 if ( !hasAnim && !jointMods.Num() ) {
4292 // no animations were updated
4296 // convert the joint quaternions to rotation matrices
4297 SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
4299 // check if we need to modify the origin
4300 if ( jointMods.Num() && ( jointMods[0]->jointnum == 0 ) ) {
4301 jointMod = jointMods[0];
4303 switch( jointMod->transform_axis ) {
4307 case JOINTMOD_LOCAL:
4308 joints[0].SetRotation( jointMod->mat * joints[0].ToMat3() );
4311 case JOINTMOD_WORLD:
4312 joints[0].SetRotation( joints[0].ToMat3() * jointMod->mat );
4315 case JOINTMOD_LOCAL_OVERRIDE:
4316 case JOINTMOD_WORLD_OVERRIDE:
4317 joints[0].SetRotation( jointMod->mat );
4321 switch( jointMod->transform_pos ) {
4325 case JOINTMOD_LOCAL:
4326 joints[0].SetTranslation( joints[0].ToVec3() + jointMod->pos );
4329 case JOINTMOD_LOCAL_OVERRIDE:
4330 case JOINTMOD_WORLD:
4331 case JOINTMOD_WORLD_OVERRIDE:
4332 joints[0].SetTranslation( jointMod->pos );
4340 // add in the model offset
4341 joints[0].SetTranslation( joints[0].ToVec3() + modelDef->GetVisualOffset() );
4343 // pointer to joint info
4344 jointParent = modelDef->JointParents();
4346 // add in any joint modifications
4347 for( i = 1; j < jointMods.Num(); j++, i++ ) {
4348 jointMod = jointMods[j];
4350 // transform any joints preceding the joint modifier
4351 SIMDProcessor->TransformJoints( joints, jointParent, i, jointMod->jointnum - 1 );
4352 i = jointMod->jointnum;
4354 parentNum = jointParent[i];
4357 switch( jointMod->transform_axis ) {
4359 joints[i].SetRotation( joints[i].ToMat3() * joints[ parentNum ].ToMat3() );
4362 case JOINTMOD_LOCAL:
4363 joints[i].SetRotation( jointMod->mat * ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) );
4366 case JOINTMOD_LOCAL_OVERRIDE:
4367 joints[i].SetRotation( jointMod->mat * joints[parentNum].ToMat3() );
4370 case JOINTMOD_WORLD:
4371 joints[i].SetRotation( ( joints[i].ToMat3() * joints[parentNum].ToMat3() ) * jointMod->mat );
4374 case JOINTMOD_WORLD_OVERRIDE:
4375 joints[i].SetRotation( jointMod->mat );
4379 // modify the position
4380 switch( jointMod->transform_pos ) {
4382 joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() );
4385 case JOINTMOD_LOCAL:
4386 joints[i].SetTranslation( joints[parentNum].ToVec3() + ( joints[i].ToVec3() + jointMod->pos ) * joints[parentNum].ToMat3() );
4389 case JOINTMOD_LOCAL_OVERRIDE:
4390 joints[i].SetTranslation( joints[parentNum].ToVec3() + jointMod->pos * joints[parentNum].ToMat3() );
4393 case JOINTMOD_WORLD:
4394 joints[i].SetTranslation( joints[parentNum].ToVec3() + joints[i].ToVec3() * joints[parentNum].ToMat3() + jointMod->pos );
4397 case JOINTMOD_WORLD_OVERRIDE:
4398 joints[i].SetTranslation( jointMod->pos );
4403 // transform the rest of the hierarchy
4404 SIMDProcessor->TransformJoints( joints, jointParent, i, numJoints - 1 );
4410 =====================
4411 idAnimator::ForceUpdate
4412 =====================
4414 void idAnimator::ForceUpdate( void ) {
4415 lastTransformTime = -1;
4420 =====================
4421 idAnimator::ClearForceUpdate
4422 =====================
4424 void idAnimator::ClearForceUpdate( void ) {
4425 forceUpdate = false;
4429 =====================
4430 idAnimator::GetJointTransform> gamex86.dll!idAnimator::ForceUpdate() Line 4268 C++
4432 =====================
4434 bool idAnimator::GetJointTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
4435 if ( !modelDef || ( jointHandle < 0 ) || ( jointHandle >= modelDef->NumJoints() ) ) {
4439 CreateFrame( currentTime, false );
4441 offset = joints[ jointHandle ].ToVec3();
4442 axis = joints[ jointHandle ].ToMat3();
4448 =====================
4449 idAnimator::GetJointLocalTransform
4450 =====================
4452 bool idAnimator::GetJointLocalTransform( jointHandle_t jointHandle, int currentTime, idVec3 &offset, idMat3 &axis ) {
4457 const idList<jointInfo_t> &modelJoints = modelDef->Joints();
4459 if ( ( jointHandle < 0 ) || ( jointHandle >= modelJoints.Num() ) ) {
4464 CreateFrame( currentTime, false );
4466 if ( jointHandle > 0 ) {
4467 idJointMat m = joints[ jointHandle ];
4468 m /= joints[ modelJoints[ jointHandle ].parentNum ];
4469 offset = m.ToVec3();
4472 offset = joints[ jointHandle ].ToVec3();
4473 axis = joints[ jointHandle ].ToMat3();
4480 =====================
4481 idAnimator::GetJointHandle
4482 =====================
4484 jointHandle_t idAnimator::GetJointHandle( const char *name ) const {
4485 if ( !modelDef || !modelDef->ModelHandle() ) {
4486 return INVALID_JOINT;
4489 return modelDef->ModelHandle()->GetJointHandle( name );
4493 =====================
4494 idAnimator::GetJointName
4495 =====================
4497 const char *idAnimator::GetJointName( jointHandle_t handle ) const {
4498 if ( !modelDef || !modelDef->ModelHandle() ) {
4502 return modelDef->ModelHandle()->GetJointName( handle );
4506 =====================
4507 idAnimator::GetChannelForJoint
4508 =====================
4510 int idAnimator::GetChannelForJoint( jointHandle_t joint ) const {
4512 gameLocal.Error( "idAnimator::GetChannelForJoint: NULL model" );
4515 if ( ( joint < 0 ) || ( joint >= numJoints ) ) {
4516 gameLocal.Error( "idAnimator::GetChannelForJoint: invalid joint num (%d)", joint );
4519 return modelDef->GetJoint( joint )->channel;
4523 =====================
4524 idAnimator::GetFirstChild
4525 =====================
4527 jointHandle_t idAnimator::GetFirstChild( const char *name ) const {
4528 return GetFirstChild( GetJointHandle( name ) );
4532 =====================
4533 idAnimator::GetFirstChild
4534 =====================
4536 jointHandle_t idAnimator::GetFirstChild( jointHandle_t jointnum ) const {
4539 const jointInfo_t *joint;
4542 return INVALID_JOINT;
4545 num = modelDef->NumJoints();
4549 joint = modelDef->GetJoint( 0 );
4550 for( i = 0; i < num; i++, joint++ ) {
4551 if ( joint->parentNum == jointnum ) {
4552 return ( jointHandle_t )joint->num;
4559 =====================
4560 idAnimator::GetJoints
4561 =====================
4563 void idAnimator::GetJoints( int *numJoints, idJointMat **jointsPtr ) {
4564 *numJoints = this->numJoints;
4565 *jointsPtr = this->joints;
4569 =====================
4570 idAnimator::GetAnimFlags
4571 =====================
4573 const animFlags_t idAnimator::GetAnimFlags( int animNum ) const {
4576 const idAnim *anim = GetAnim( animNum );
4578 return anim->GetAnimFlags();
4581 memset( &result, 0, sizeof( result ) );
4586 =====================
4587 idAnimator::NumFrames
4588 =====================
4590 int idAnimator::NumFrames( int animNum ) const {
4591 const idAnim *anim = GetAnim( animNum );
4593 return anim->NumFrames();
4600 =====================
4601 idAnimator::NumSyncedAnims
4602 =====================
4604 int idAnimator::NumSyncedAnims( int animNum ) const {
4605 const idAnim *anim = GetAnim( animNum );
4607 return anim->NumAnims();
4614 =====================
4615 idAnimator::AnimName
4616 =====================
4618 const char *idAnimator::AnimName( int animNum ) const {
4619 const idAnim *anim = GetAnim( animNum );
4621 return anim->Name();
4628 =====================
4629 idAnimator::AnimFullName
4630 =====================
4632 const char *idAnimator::AnimFullName( int animNum ) const {
4633 const idAnim *anim = GetAnim( animNum );
4635 return anim->FullName();
4642 =====================
4643 idAnimator::AnimLength
4644 =====================
4646 int idAnimator::AnimLength( int animNum ) const {
4647 const idAnim *anim = GetAnim( animNum );
4649 return anim->Length();
4656 =====================
4657 idAnimator::TotalMovementDelta
4658 =====================
4660 const idVec3 &idAnimator::TotalMovementDelta( int animNum ) const {
4661 const idAnim *anim = GetAnim( animNum );
4663 return anim->TotalMovementDelta();
4669 /***********************************************************************
4673 ***********************************************************************/
4676 =====================
4677 ANIM_GetModelDefFromEntityDef
4678 =====================
4680 const idDeclModelDef *ANIM_GetModelDefFromEntityDef( const idDict *args ) {
4681 const idDeclModelDef *modelDef;
4683 idStr name = args->GetString( "model" );
4684 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name, false ) );
4685 if ( modelDef && modelDef->ModelHandle() ) {
4693 =====================
4694 idGameEdit::ANIM_GetModelFromEntityDef
4695 =====================
4697 idRenderModel *idGameEdit::ANIM_GetModelFromEntityDef( const idDict *args ) {
4698 idRenderModel *model;
4699 const idDeclModelDef *modelDef;
4703 idStr name = args->GetString( "model" );
4704 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name, false ) );
4706 model = modelDef->ModelHandle();
4710 model = renderModelManager->FindModel( name );
4713 if ( model && model->IsDefaultModel() ) {
4721 =====================
4722 idGameEdit::ANIM_GetModelFromEntityDef
4723 =====================
4725 idRenderModel *idGameEdit::ANIM_GetModelFromEntityDef( const char *classname ) {
4728 args = gameLocal.FindEntityDefDict( classname, false );
4733 return ANIM_GetModelFromEntityDef( args );
4737 =====================
4738 idGameEdit::ANIM_GetModelOffsetFromEntityDef
4739 =====================
4741 const idVec3 &idGameEdit::ANIM_GetModelOffsetFromEntityDef( const char *classname ) {
4743 const idDeclModelDef *modelDef;
4745 args = gameLocal.FindEntityDefDict( classname, false );
4750 modelDef = ANIM_GetModelDefFromEntityDef( args );
4755 return modelDef->GetVisualOffset();
4759 =====================
4760 idGameEdit::ANIM_GetModelFromName
4761 =====================
4763 idRenderModel *idGameEdit::ANIM_GetModelFromName( const char *modelName ) {
4764 const idDeclModelDef *modelDef;
4765 idRenderModel *model;
4768 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelName, false ) );
4770 model = modelDef->ModelHandle();
4773 model = renderModelManager->FindModel( modelName );
4779 =====================
4780 idGameEdit::ANIM_GetAnimFromEntityDef
4781 =====================
4783 const idMD5Anim *idGameEdit::ANIM_GetAnimFromEntityDef( const char *classname, const char *animname ) {
4785 const idMD5Anim *md5anim;
4788 const char *modelname;
4789 const idDeclModelDef *modelDef;
4791 args = gameLocal.FindEntityDefDict( classname, false );
4797 modelname = args->GetString( "model" );
4798 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4800 animNum = modelDef->GetAnim( animname );
4802 anim = modelDef->GetAnim( animNum );
4804 md5anim = anim->MD5Anim( 0 );
4812 =====================
4813 idGameEdit::ANIM_GetNumAnimsFromEntityDef
4814 =====================
4816 int idGameEdit::ANIM_GetNumAnimsFromEntityDef( const idDict *args ) {
4817 const char *modelname;
4818 const idDeclModelDef *modelDef;
4820 modelname = args->GetString( "model" );
4821 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4823 return modelDef->NumAnims();
4829 =====================
4830 idGameEdit::ANIM_GetAnimNameFromEntityDef
4831 =====================
4833 const char *idGameEdit::ANIM_GetAnimNameFromEntityDef( const idDict *args, int animNum ) {
4834 const char *modelname;
4835 const idDeclModelDef *modelDef;
4837 modelname = args->GetString( "model" );
4838 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, modelname, false ) );
4840 const idAnim* anim = modelDef->GetAnim( animNum );
4842 return anim->FullName();
4849 =====================
4850 idGameEdit::ANIM_GetAnim
4851 =====================
4853 const idMD5Anim *idGameEdit::ANIM_GetAnim( const char *fileName ) {
4854 return animationLib.GetAnim( fileName );
4858 =====================
4859 idGameEdit::ANIM_GetLength
4860 =====================
4862 int idGameEdit::ANIM_GetLength( const idMD5Anim *anim ) {
4866 return anim->Length();
4870 =====================
4871 idGameEdit::ANIM_GetNumFrames
4872 =====================
4874 int idGameEdit::ANIM_GetNumFrames( const idMD5Anim *anim ) {
4878 return anim->NumFrames();
4882 =====================
4883 idGameEdit::ANIM_CreateAnimFrame
4884 =====================
4886 void idGameEdit::ANIM_CreateAnimFrame( const idRenderModel *model, const idMD5Anim *anim, int numJoints, idJointMat *joints, int time, const idVec3 &offset, bool remove_origin_offset ) {
4889 const idMD5Joint *md5joints;
4892 if ( !model || model->IsDefaultModel() || !anim ) {
4896 if ( numJoints != model->NumJoints() ) {
4897 gameLocal.Error( "ANIM_CreateAnimFrame: different # of joints in renderEntity_t than in model (%s)", model->Name() );
4900 if ( !model->NumJoints() ) {
4901 // FIXME: Print out a warning?
4906 gameLocal.Error( "ANIM_CreateAnimFrame: NULL joint frame pointer on model (%s)", model->Name() );
4909 if ( numJoints != anim->NumJoints() ) {
4910 gameLocal.Warning( "Model '%s' has different # of joints than anim '%s'", model->Name(), anim->Name() );
4911 for( i = 0; i < numJoints; i++ ) {
4912 joints[i].SetRotation( mat3_identity );
4913 joints[i].SetTranslation( offset );
4918 // create index for all joints
4919 index = ( int * )_alloca16( numJoints * sizeof( int ) );
4920 for ( i = 0; i < numJoints; i++ ) {
4925 anim->ConvertTimeToFrame( time, 1, frame );
4926 idJointQuat *jointFrame = ( idJointQuat * )_alloca16( numJoints * sizeof( *jointFrame ) );
4927 anim->GetInterpolatedFrame( frame, jointFrame, index, numJoints );
4929 // convert joint quaternions to joint matrices
4930 SIMDProcessor->ConvertJointQuatsToJointMats( joints, jointFrame, numJoints );
4932 // first joint is always root of entire hierarchy
4933 if ( remove_origin_offset ) {
4934 joints[0].SetTranslation( offset );
4936 joints[0].SetTranslation( joints[0].ToVec3() + offset );
4939 // transform the children
4940 md5joints = model->GetJoints();
4941 for( i = 1; i < numJoints; i++ ) {
4942 joints[i] *= joints[ md5joints[i].parent - md5joints ];
4947 =====================
4948 idGameEdit::ANIM_CreateMeshForAnim
4949 =====================
4951 idRenderModel *idGameEdit::ANIM_CreateMeshForAnim( idRenderModel *model, const char *classname, const char *animname, int frame, bool remove_origin_offset ) {
4955 idRenderModel *newmodel;
4956 const idMD5Anim *md5anim;
4962 const idDeclModelDef *modelDef;
4964 if ( !model || model->IsDefaultModel() ) {
4968 args = gameLocal.FindEntityDefDict( classname, false );
4973 memset( &ent, 0, sizeof( ent ) );
4976 ent.suppressSurfaceInViewID = 0;
4978 modelDef = ANIM_GetModelDefFromEntityDef( args );
4980 animNum = modelDef->GetAnim( animname );
4984 anim = modelDef->GetAnim( animNum );
4988 md5anim = anim->MD5Anim( 0 );
4989 ent.customSkin = modelDef->GetDefaultSkin();
4990 offset = modelDef->GetVisualOffset();
4992 filename = animname;
4993 filename.ExtractFileExtension( extension );
4994 if ( !extension.Length() ) {
4995 animname = args->GetString( va( "anim %s", animname ) );
4998 md5anim = animationLib.GetAnim( animname );
5006 temp = args->GetString( "skin", "" );
5008 ent.customSkin = declManager->FindSkin( temp );
5011 ent.numJoints = model->NumJoints();
5012 ent.joints = ( idJointMat * )Mem_Alloc16( ent.numJoints * sizeof( *ent.joints ) );
5014 ANIM_CreateAnimFrame( model, md5anim, ent.numJoints, ent.joints, FRAME2MS( frame ), offset, remove_origin_offset );
5016 newmodel = model->InstantiateDynamicModel( &ent, NULL, NULL );
5018 Mem_Free16( ent.joints );