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