1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADAMax. 5 6 Portions of the code are: 7 Copyright (c) 2005-2007 Feeling Software Inc. 8 Copyright (c) 2005-2007 Sony Computer Entertainment America 9 10 Based on the 3dsMax COLLADASW Tools: 11 Copyright (c) 2005-2006 Autodesk Media Entertainment 12 13 Licensed under the MIT Open Source License, 14 for details please see LICENSE file or the website 15 http://www.opensource.org/licenses/mit-license.php 16 */ 17 18 #include "COLLADAMaxStableHeaders.h" 19 20 #include "COLLADASWStreamWriter.h" 21 #include "COLLADASWSource.h" 22 #include "Math/COLLADABUMathUtils.h" 23 24 #include "COLLADAMaxAnimationExporter.h" 25 #include "COLLADAMaxExportSceneGraph.h" 26 27 #include <max.h> 28 #include <istdplug.h> 29 #include <control.h> 30 #include <units.h> 31 32 33 namespace COLLADAMax 34 { 35 36 37 //--------------------------------------------------------------- Animation(Control * controller,const String & id,const String & sid,const String * parameter,int type,ConversionFunctor * conversionFunctor)38 Animation::Animation ( Control * controller, const String & id, const String & sid, const String * parameter, int type, ConversionFunctor* conversionFunctor ) 39 : mController ( controller ), 40 mINode(0), 41 mId ( id ), 42 mSid ( sid ), 43 mParameters ( parameter ), 44 mMatrixIndex(-1), 45 mType ( type ), 46 mConversionFunctor( conversionFunctor ? conversionFunctor->clone() : 0 ), 47 mInputTypeFlags(NONE) 48 {} 49 50 51 //--------------------------------------------------------------- Animation(Control * controller,const String & id,const String & sid,int matrixIndex,int type,ConversionFunctor * conversionFunctor)52 Animation::Animation ( Control * controller, const String & id, const String & sid, int matrixIndex, int type, ConversionFunctor* conversionFunctor ) 53 : mController ( controller ), 54 mINode(0), 55 mId ( id ), 56 mSid ( sid ), 57 mParameters ( 0 ), 58 mMatrixIndex(matrixIndex), 59 mType ( type ), 60 mConversionFunctor( conversionFunctor ? conversionFunctor->clone() : 0 ), 61 mInputTypeFlags(NONE) 62 {} 63 64 65 66 //--------------------------------------------------------------- Animation(INode * iNode,const String & id,const String & sid,const String * parameter,int type,ConversionFunctor * conversionFunctor)67 Animation::Animation ( INode * iNode, const String & id, const String & sid, const String * parameter, int type, ConversionFunctor* conversionFunctor ) 68 : 69 mController(0), 70 mINode ( iNode ), 71 mId ( id ), 72 mSid ( sid ), 73 mParameters ( parameter ), 74 mMatrixIndex(-1), 75 mType ( type ), 76 mConversionFunctor( conversionFunctor ? conversionFunctor->clone() : 0 ), 77 mInputTypeFlags(NONE) 78 {} 79 80 Animation(const Animation & other)81 Animation::Animation( const Animation& other ): 82 mController (other.mController), 83 mINode (other.mINode), 84 mId( other.mId), 85 mSid(other.mSid), 86 mParameters(other.mParameters), 87 mMatrixIndex(other.mMatrixIndex), 88 mType(other.mType), 89 mInputTypeFlags(other.mInputTypeFlags), 90 mConversionFunctor ( other.mConversionFunctor ? other.mConversionFunctor->clone() : 0) 91 {} 92 operator =(const Animation & other)93 const Animation& Animation::operator=( const Animation& other ) 94 { 95 mController = other.mController; 96 mINode = other.mINode; 97 mId = other.mId; 98 mSid = other.mSid; 99 mParameters = other.mParameters; 100 mMatrixIndex = other.mMatrixIndex; 101 mType = other.mType; 102 mInputTypeFlags = other.mInputTypeFlags; 103 mConversionFunctor = other.mConversionFunctor ? other.mConversionFunctor->clone() : 0; 104 return *this; 105 } 106 107 //--------------------------------------------------------------- getDimension() const108 int Animation::getDimension() const 109 { 110 switch ( mType ) 111 { 112 113 case FLOAT: 114 case POSITION_X: 115 case POSITION_Y: 116 case POSITION_Z: 117 case ROTATION_X: 118 case ROTATION_Y: 119 case ROTATION_Z: 120 return 1; 121 122 case FLOAT3: 123 return 3; 124 125 case SCALE_ROT_AXIS_R: 126 case SCALE_ROT_AXIS: 127 case FLOAT4: 128 return 4; 129 130 case FLOAT4x4: 131 return 16; 132 133 default: 134 return 0; 135 } 136 } 137 ~Animation()138 Animation::~Animation() 139 { 140 delete mConversionFunctor; 141 } 142 143 const float AnimationExporter::DEFAULT_INLENGHT = 0.333f; 144 const float AnimationExporter::DEFAULT_OUTLENGHT = 0.333f; 145 const float AnimationExporter::DEFAULT_INLENGHT_FLOAT = AnimationExporter::DEFAULT_INLENGHT; 146 147 float AnimationExporter::DEFAULT_INLENGHT_POINTX_FLOAT_ARRAY[4] = {AnimationExporter::DEFAULT_INLENGHT, AnimationExporter::DEFAULT_INLENGHT, AnimationExporter::DEFAULT_INLENGHT, AnimationExporter::DEFAULT_INLENGHT}; 148 149 const float AnimationExporter::DEFAULT_OUTLENGHT_FLOAT = AnimationExporter::DEFAULT_OUTLENGHT; 150 float AnimationExporter::DEFAULT_OUTLENGHT_POINTX_FLOAT_ARRAY[4] = {AnimationExporter::DEFAULT_OUTLENGHT, AnimationExporter::DEFAULT_OUTLENGHT, AnimationExporter::DEFAULT_OUTLENGHT, AnimationExporter::DEFAULT_OUTLENGHT}; 151 152 153 const float AnimationExporter::mTimeFactor = 1.0f / ( GetTicksPerFrame() * GetFrameRate() ); 154 155 156 157 //--------------------------------------------------------------- AnimationExporter(COLLADASW::StreamWriter * streamWriter,DocumentExporter * documentExporter)158 AnimationExporter::AnimationExporter ( COLLADASW::StreamWriter * streamWriter, DocumentExporter * documentExporter ) 159 : COLLADASW::LibraryAnimations ( streamWriter ), 160 mDocumentExporter ( documentExporter ), 161 mClipExporter( streamWriter) 162 {} 163 164 //--------------------------------------------------------------- getPreviousTime(const int & i,Control * controller) const165 TimeValue AnimationExporter::getPreviousTime ( const int & i, Control * controller ) const 166 { 167 return ( i > 0 ) ? controller->GetKeyTime ( i - 1 ) : controller->GetKeyTime ( i ) - TimeValue ( 1.0f / mTimeFactor ); 168 } 169 170 //--------------------------------------------------------------- getNextTime(const int & i,const int & keyCount,Control * controller) const171 TimeValue AnimationExporter::getNextTime ( const int & i, const int & keyCount, Control * controller ) const 172 { 173 return ( i < keyCount - 1 ) ? controller->GetKeyTime ( i + 1 ) : controller->GetKeyTime ( i ) + TimeValue ( 1.0f / mTimeFactor ); 174 } 175 176 //--------------------------------------------------------------- forceSampleMatrices(INode * iNode)177 bool AnimationExporter::forceSampleMatrices(INode* iNode) 178 { 179 if ( iNode ) 180 { 181 Control* controller = iNode->GetTMController(); 182 // The -only- class we can hope to export without sampling is the PRS controller 183 if ( controller ) 184 return (controller->ClassID() != Class_ID(PRS_CONTROL_CLASS_ID, 0) || findConstraint(controller)); 185 } 186 return false; 187 } 188 189 // Function searches controller and all subanims for presence of a Constraint. 190 // This is bit of a cheap fix, a slightly better option may be to include 191 // parent offset calculation in rotation/position sampling (like Matrix sampling). 192 //--------------------------------------------------------------- findConstraint(Animatable * controller)193 bool AnimationExporter::findConstraint(Animatable* controller) 194 { 195 if (controller->SuperClassID() == CTRL_FLOAT_CLASS_ID) 196 return false; 197 Class_ID classId = controller->ClassID(); 198 if (classId.PartB() == 0) 199 { 200 unsigned long classIdPartA = classId.PartA(); 201 if (classIdPartA == POSITION_CONSTRAINT_CLASS_ID || 202 classIdPartA == ORIENTATION_CONSTRAINT_CLASS_ID || 203 classIdPartA == LOOKAT_CONSTRAINT_CLASS_ID) 204 { 205 return true; 206 } 207 } 208 209 int SubcontrollerCount = controller->NumSubs(); 210 for (int i = 0; i < SubcontrollerCount; i++) 211 { 212 Animatable* subController = controller->SubAnim(i); 213 if (subController ) 214 { 215 if (findConstraint(subController)) 216 return true; 217 } 218 } 219 return false; 220 } 221 222 223 //--------------------------------------------------------------- doExport()224 void AnimationExporter::doExport() 225 { 226 if (!mAnimationList.empty() || !mAnimationMap.empty()) 227 { 228 if (!mAnimationList.empty()) { 229 openAnimation(); 230 231 for (AnimationList::iterator it = mAnimationList.begin(); it != mAnimationList.end(); ++it) 232 exportSources(*it); 233 234 for (AnimationList::iterator it = mAnimationList.begin(); it != mAnimationList.end(); ++it) 235 exportSampler(*it); 236 237 for (AnimationList::iterator it = mAnimationList.begin(); it != mAnimationList.end(); ++it) 238 exportChannel(*it); 239 240 241 closeAnimation(); 242 } 243 #if defined(MAX_RELEASE_R17) && (MAX_RELEASE >= MAX_RELEASE_R17) 244 for (auto& animPair : mAnimationMap) { 245 String animName = animPair.first; 246 openAnimation(animName + "_animation", animName); 247 for (auto& anim : animPair.second) { 248 exportSources(anim); 249 } 250 for (auto& anim : animPair.second) { 251 exportSampler(anim); 252 } 253 for (auto& anim : animPair.second) { 254 exportChannel(anim); 255 } 256 closeAnimation(); 257 } 258 #endif 259 260 closeLibrary(); 261 262 #if defined(MAX_RELEASE_R17) && (MAX_RELEASE >= MAX_RELEASE_R17) 263 // Export the animation clips to go with the named animations 264 if (mAnimationMap.size() != 0) { 265 mClipExporter.open(); 266 for (auto& animPair : mAnimationMap) { 267 String animName = animPair.first; 268 COLLADASW::ColladaAnimationClip clip(animName + "_clip", animName); 269 clip.setInstancedAnimation(animName + "_animation"); 270 mClipExporter.addClip(clip); 271 } 272 mClipExporter.close(); 273 } 274 #endif 275 } 276 } 277 278 279 //--------------------------------------------------------------- addAnimatedFloat(Control * controller,const String & id,const String & sid,const String parameters[],bool forceFullCheck,ConversionFunctor * conversionFunctor)280 bool AnimationExporter::addAnimatedFloat ( Control * controller, const String & id, const String & sid, const String parameters[], bool forceFullCheck, ConversionFunctor* conversionFunctor) 281 { 282 if ( !isAnimated(controller) ) 283 return false; 284 285 Animation animation(controller, id, sid, parameters, Animation::FLOAT, conversionFunctor); 286 287 if ( !forceFullCheck || isAnimated(animation, true) ) 288 { 289 addAnimation(animation); 290 return true; 291 } 292 return false; 293 } 294 295 296 //--------------------------------------------------------------- addAnimatedFloat(Control * controller,const String & id,const String & sid,int matrixIndex,bool forceFullCheck,ConversionFunctor * conversionFunctor)297 bool AnimationExporter::addAnimatedFloat ( Control * controller, const String & id, const String & sid, int matrixIndex, bool forceFullCheck, ConversionFunctor* conversionFunctor) 298 { 299 if ( !isAnimated(controller) ) 300 return false; 301 302 Animation animation(controller, id, sid, matrixIndex, Animation::FLOAT, conversionFunctor); 303 304 if ( !forceFullCheck || isAnimated(animation, true) ) 305 { 306 addAnimation(animation); 307 return true; 308 } 309 return false; 310 } 311 312 313 314 //--------------------------------------------------------------- addAnimatedPoint3(Control * controller,const String & layerName,const String & id,const String & sid,const String parameters[],bool forceFullCheck,ConversionFunctor * conversionFunctor)315 bool AnimationExporter::addAnimatedPoint3 ( Control * controller, const String& layerName, const String & id, const String & sid, const String parameters[], bool forceFullCheck, ConversionFunctor* conversionFunctor ) 316 { 317 if ( !isAnimated(controller)) 318 return false; 319 320 bool animated = false; 321 322 Control * subControllers[ 3 ] = {controller->GetXController(), controller->GetYController(), controller->GetZController() }; 323 324 // First, Try to extract animations from the component controllers 325 326 if ( subControllers[ 0 ] && subControllers[ 1 ] && subControllers[ 2 ] ) 327 { 328 for ( int i = 0; i < 3; ++i ) 329 { 330 if ( isAnimated ( subControllers[ i ] ) ) 331 { 332 Animation animation ( subControllers[ i ], id, sid, parameters + i, Animation::FLOAT, conversionFunctor ); 333 if ( !forceFullCheck || isAnimated(animation, true) ) 334 { 335 if (layerName == "") 336 addAnimation(animation); 337 else 338 addNamedAnimation(animation, layerName); 339 340 animated = true; 341 } 342 } 343 } 344 } 345 else if ( isAnimated ( controller ) ) 346 { 347 // Else, with no subs, try and export ourselves as keyframes 348 Animation animation ( controller, id, sid, parameters, Animation::FLOAT3, conversionFunctor ); 349 if ( !forceFullCheck || isAnimated(animation, true) ) 350 { 351 if (layerName == "") 352 addAnimation(animation); 353 else 354 addNamedAnimation(animation, layerName); 355 356 animated = true; 357 } 358 } 359 return animated; 360 } 361 362 363 //--------------------------------------------------------------- addAnimatedPoint4(Control * controller,const String & id,const String & sid,const String parameters[],bool forceFullCheck,ConversionFunctor * conversionFunctor)364 bool AnimationExporter::addAnimatedPoint4 ( Control * controller, const String & id, const String & sid, const String parameters[], bool forceFullCheck, ConversionFunctor* conversionFunctor ) 365 { 366 bool animated = false; 367 368 Control * subControllers[ 4 ] = {controller->GetXController(), controller->GetYController(), controller->GetZController(), controller->GetWController() }; 369 370 // First, Try to extract animations from the component controllers 371 372 if ( subControllers[ 0 ] || subControllers[ 1 ] || subControllers[ 2 ] || subControllers[ 3 ] ) 373 { 374 for ( int i = 0; i < 4; ++i ) 375 { 376 if ( isAnimated ( subControllers[ i ] ) ) 377 { 378 Animation animation ( subControllers[ i ], id, sid, parameters + i, Animation::FLOAT, conversionFunctor ); 379 if ( !forceFullCheck || isAnimated(animation, true) ) 380 { 381 addAnimation ( animation ); 382 animated = true; 383 } 384 } 385 } 386 } 387 388 else if ( isAnimated ( controller ) ) 389 { 390 // Else, with no subs, try and export ourselves as keyframes 391 Animation animation ( controller, id, sid, parameters, Animation::FLOAT4, conversionFunctor ); 392 if ( !forceFullCheck || isAnimated(animation, true) ) 393 { 394 addAnimation ( animation ); 395 animated = true; 396 } 397 } 398 399 return animated; 400 } 401 402 403 //--------------------------------------------------------------- addAnimatedAngle(Control * controller,const String & layerName,const String & id,const String & sid,const String parameters[],int animatedAngle,bool forceFullCheck)404 bool AnimationExporter::addAnimatedAngle ( Control * controller, const String& layerName, const String & id, const String & sid, const String parameters[], int animatedAngle, bool forceFullCheck ) 405 { 406 if ( !isAnimated ( controller ) ) 407 return false; 408 409 // maybe this rotation controller doesn't have XYZ components 410 Control * xyzController = NULL; 411 412 switch ( animatedAngle ) 413 { 414 415 case Animation::ROTATION_X: 416 xyzController = controller->GetXController(); 417 break; 418 419 case Animation::ROTATION_Y: 420 xyzController = controller->GetYController(); 421 break; 422 423 case Animation::ROTATION_Z: 424 xyzController = controller->GetZController(); 425 break; 426 } 427 428 if ( xyzController != NULL ) 429 controller = xyzController; 430 431 Animation animation ( controller, id, sid, parameters, animatedAngle, &ConversionFunctors::radToDeg ); 432 433 if ( !forceFullCheck || isAnimated(animation, true) ) 434 { 435 if (layerName == "") 436 addAnimation(animation); 437 else 438 addNamedAnimation(animation, layerName); 439 440 return true; 441 } 442 443 return false; 444 } 445 446 447 //--------------------------------------------------------------- addAnimatedAxisAngle(Control * controller,const String & id,const String & sid,const String parameters[],int type,bool forceFullCheck)448 bool AnimationExporter::addAnimatedAxisAngle ( Control * controller, const String & id, const String & sid, const String parameters[], int type, bool forceFullCheck ) 449 { 450 if ( !isAnimated ( controller ) ) 451 return false; 452 453 Animation animation ( controller, id, sid, parameters, type); 454 if ( !forceFullCheck || isAnimated(animation, true) ) 455 { 456 addAnimation ( animation ); 457 return true; 458 } 459 return false; 460 } 461 462 463 //--------------------------------------------------------------- addAnimatedFloat4x4(INode * node,const String & id,const String & sid,const String parameters[],bool forceFullCheck)464 bool AnimationExporter::addAnimatedFloat4x4 ( INode * node, const String & id, const String & sid, const String parameters[], bool forceFullCheck ) 465 { 466 Animation animation ( node, id, sid, parameters, Animation::FLOAT4x4); 467 468 if ( !forceFullCheck || isAnimated(animation, true) ) 469 { 470 addAnimation ( animation ); 471 return true; 472 } 473 474 return false; 475 } 476 477 478 //--------------------------------------------------------------- addAnimatedParameter(IParamBlock * parameterBlock,int parameterId,const String & id,const String & sid,const String parameters[],bool forceFullCheck,ConversionFunctor * conversionFunctor)479 bool AnimationExporter::addAnimatedParameter( IParamBlock * parameterBlock, int parameterId, const String & id, const String & sid, const String parameters[], bool forceFullCheck, ConversionFunctor* conversionFunctor ) 480 { 481 ParamType type = parameterBlock->GetParameterType(parameterId); 482 Control* controller = parameterBlock->GetController(parameterId); 483 484 if ( !isAnimated(controller) ) 485 return false; 486 487 switch ( type ) 488 { 489 case TYPE_FLOAT: 490 return addAnimatedFloat(controller, id, sid, parameters, forceFullCheck, conversionFunctor); 491 case TYPE_COLOR: 492 case TYPE_RGBA: 493 return addAnimatedPoint4(controller, id, sid, parameters, forceFullCheck, conversionFunctor); 494 } 495 return false; 496 } 497 498 499 //--------------------------------------------------------------- addAnimatedParameter(IParamBlock2 * parameterBlock,int parameterId,const String & id,const String & sid,const String parameters[],bool forceFullCheck,ConversionFunctor * conversionFunctor)500 bool AnimationExporter::addAnimatedParameter( IParamBlock2 * parameterBlock, int parameterId, const String & id, const String & sid, const String parameters[], bool forceFullCheck, ConversionFunctor* conversionFunctor ) 501 { 502 ParamType2 type = parameterBlock->GetParameterType(parameterId); 503 int animationNumber = parameterBlock->GetAnimNum(parameterId); 504 if (animationNumber == -1) 505 return false; 506 507 #ifdef MAX_2012_OR_NEWER 508 Control *controller = parameterBlock->GetControllerByIndex(animationNumber); 509 #else 510 Control *controller = parameterBlock->GetController(animationNumber); 511 #endif 512 513 if ( !isAnimated(controller) ) 514 return false; 515 516 switch ( type ) 517 { 518 case TYPE_FLOAT: 519 return addAnimatedFloat(controller, id, sid, parameters, forceFullCheck, conversionFunctor); 520 case TYPE_COLOR: 521 case TYPE_RGBA: 522 return addAnimatedPoint4(controller, id, sid, parameters, forceFullCheck, conversionFunctor); 523 } 524 return false; 525 } 526 527 528 /* void AnimationExporter::addAnimation4( Control * controller, const String & id, const String & sid, const String parameters[]) 529 { 530 Control * controllers[4] = {controller->GetXController(), controller->GetYController(), controller->GetZController(), controller->GetWController()}; 531 for ( int i = 0; i<4; ++i) 532 { 533 if ( isAnimated(controllers[i]) ) 534 { 535 Animation animation(controllers[i], id, sid, parameters[i]); 536 addAnimation(animation); 537 } 538 } 539 } 540 541 */ 542 543 //--------------------------------------------------------------- isAnimated(Control * controller)544 bool AnimationExporter::isAnimated ( Control * controller ) 545 { 546 return controller && controller->IsAnimated(); 547 } 548 549 550 //--------------------------------------------------------------- isAnimated(const Animation & animation,bool forceFullCheck)551 bool AnimationExporter::isAnimated ( const Animation& animation, bool forceFullCheck ) 552 { 553 Control* controller = animation.getController(); 554 INode* iNode = animation.getNode(); 555 556 bool animated = isAnimated(controller) || iNode; 557 558 if ( !animated ) 559 return false; 560 561 if ( forceFullCheck ) 562 return checkIfIsAnimated(animation); 563 564 return animated; 565 } 566 567 isAnimated(IParamBlock * paramBlock,int parameterId)568 bool AnimationExporter::isAnimated( IParamBlock * paramBlock, int parameterId ) 569 { 570 Control* controller = paramBlock->GetController(parameterId); 571 return isAnimated(controller); 572 } 573 isAnimated(IParamBlock2 * paramBlock,int parameterId)574 bool AnimationExporter::isAnimated( IParamBlock2 * paramBlock, int parameterId ) 575 { 576 577 int animationNumber = paramBlock->GetAnimNum(parameterId); 578 if (animationNumber == -1) 579 return false; 580 //int pi = paramBlock->AnimNumToParamNum(animationNumber, tabIndex); 581 #ifdef MAX_2012_OR_NEWER 582 Control *controller = paramBlock->GetControllerByIndex(animationNumber); 583 #else 584 Control *controller = paramBlock->GetController(animationNumber); 585 #endif 586 587 return isAnimated(controller); 588 } 589 590 591 592 /** @TODO implement a test that check if an animations animated, i.e. if the values change */ 593 //--------------------------------------------------------------- checkIfIsAnimated(const Animation & animation)594 bool AnimationExporter::checkIfIsAnimated ( const Animation& animation ) 595 { 596 Control * controller = animation.getController(); 597 INode * iNode = animation.getNode(); 598 599 bool isSampling = !controller || mDocumentExporter->getOptions().getSampleAnimation(); 600 601 IKeyControl * keyInterface = 0; 602 603 if (!isSampling) 604 { 605 keyInterface = GetKeyControlInterface ( controller ); 606 if ( !keyInterface ) 607 isSampling = true; 608 else if (keyInterface->GetNumKeys() <= 1) 609 return false; 610 } 611 612 if ( !isSampling ) 613 { 614 Class_ID classId = controller->ClassID(); 615 616 if ( classId.PartB() != 0 ) 617 { 618 // This is not a Max controller, sample it. 619 // The only max controllers that have non-zero 620 // values are not keyable (attach, link, etc). 621 isSampling = true; 622 } 623 else if ( keyInterface && keyInterface->GetNumKeys() > 0 ) 624 { 625 int keyCount = keyInterface->GetNumKeys(); 626 627 switch ( classId.PartA() ) 628 { 629 630 case LININTERP_FLOAT_CLASS_ID: 631 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getFloatValue<ILinFloatKey> ); 632 break; 633 634 case LININTERP_POSITION_CLASS_ID: 635 if ( animation.getDimension() == 1 ) 636 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getPointXSingleValue<ILinPoint3Key> ); 637 else 638 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getPointXValue<3, ILinPoint3Key> ); 639 640 break; 641 642 case LININTERP_ROTATION_CLASS_ID: 643 if ( animation.getDimension() == 1 ) 644 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getRotationSingleValue<ILinRotKey> ); 645 else 646 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getRotationValue<ILinRotKey> ); 647 break; 648 649 case HYBRIDINTERP_FLOAT_CLASS_ID: 650 // return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getFloatValue<IBezFloatKey> ); 651 case HYBRIDINTERP_POINT3_CLASS_ID: 652 case HYBRIDINTERP_POSITION_CLASS_ID: 653 case HYBRIDINTERP_SCALE_CLASS_ID: 654 case HYBRIDINTERP_COLOR_CLASS_ID: 655 /* if ( animation.getDimension() == 1 ) 656 { 657 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getPointXSingleValue<IBezPoint3Key> ); 658 } 659 else 660 { 661 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getPointXValue<3, IBezPoint3Key> ); 662 }*/ 663 case HYBRIDINTERP_ROTATION_CLASS_ID: 664 /* if ( animation.getDimension() == 1 ) 665 { 666 mKeyValueList.reserve( keyInterface->GetNumKeys() ); 667 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getRotationSingleValuePatchEuler ); 668 } 669 else 670 { 671 mKeyValueList.reserve( 3 * keyInterface->GetNumKeys() ); 672 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getRotationValuePatchEuler ); 673 } 674 mKeyValueList.clear();*/ 675 return true; //For hybrid controllers its more complicated te test if they are constant (in-outtangens) 676 break; 677 case LININTERP_SCALE_CLASS_ID: 678 if ( animation.getType() == Animation::SCALE) 679 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getPointXValue<3, IBezScaleKey> ); 680 else if ( animation.getType() == Animation::SCALE_ROT_AXIS ) 681 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getScaleRotationAxisValue<IBezScaleKey, false> ); 682 else if ( animation.getType() == Animation::SCALE_ROT_AXIS_R ) 683 return checkIfIsAnimated ( animation, keyInterface, &AnimationExporter::getScaleRotationAxisValue<IBezScaleKey, true> ); 684 break; 685 default: 686 isSampling = true; 687 break; 688 } 689 } 690 } 691 692 if ( isSampling ) 693 { 694 int ticksPerFrame = GetTicksPerFrame(); 695 TimeValue startTime = mDocumentExporter->getOptions().getAnimationStart(); 696 TimeValue endTime = mDocumentExporter->getOptions().getAnimationEnd() + 1; 697 698 if ( endTime > startTime ) 699 { 700 if ( controller ) 701 { 702 SClass_ID type = controller->SuperClassID(); 703 switch (type) 704 { 705 case CTRL_FLOAT_CLASS_ID: 706 return checkIfSampledFloatIsAnimated(animation, keyInterface, startTime, endTime, ticksPerFrame); 707 break; 708 case CTRL_POINT3_CLASS_ID: 709 case CTRL_POSITION_CLASS_ID: 710 return checkIfSampledPoint3IsAnimated(animation, keyInterface, startTime, endTime, ticksPerFrame); 711 break; 712 case CTRL_ROTATION_CLASS_ID: 713 return checkIfSampledRotationIsAnimated(animation, keyInterface, startTime, endTime, ticksPerFrame); 714 break; 715 } 716 } 717 else if ( animation.getNode() ) 718 { 719 return checkIfSampledTransformationIsAnimated(animation, keyInterface, startTime, endTime, ticksPerFrame); 720 } 721 } 722 723 } 724 725 return false; 726 } 727 728 729 //--------------------------------------------------------------- checkIfIsAnimated(const Animation & animation,IKeyControl * keyInterface,OutputValueFunctionPtr outputValueFunction)730 bool AnimationExporter::checkIfIsAnimated ( const Animation & animation, IKeyControl* keyInterface, OutputValueFunctionPtr outputValueFunction ) 731 { 732 int keyCount = keyInterface->GetNumKeys(); 733 int keyLength = animation.getDimension(); 734 735 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 736 737 bool animated = false; 738 739 float * firstKeyBuffer = new float[ keyLength ]; 740 741 float * keyBuffer = new float[ keyLength ]; 742 743 for ( int i = 0; i < keyCount && !animated; ++i ) 744 { 745 (this->*outputValueFunction) ( keyBuffer, keyInterface, i, animation ); 746 747 for ( int j = 0; j < keyLength && !animated; ++j ) 748 { 749 if ( conversionFunctor ) 750 keyBuffer[j] = (*conversionFunctor) ( keyBuffer[ j ] ); 751 752 if ( i == 0 ) 753 std::swap(firstKeyBuffer, keyBuffer); 754 else if ( !COLLADASW::MathUtils::equals(keyBuffer[j], firstKeyBuffer[j]) ) 755 animated = true; 756 } 757 } 758 759 delete[] keyBuffer; 760 delete[] firstKeyBuffer; 761 762 return animated; 763 } 764 765 766 //--------------------------------------------------------------- checkIfSampledFloatIsAnimated(const Animation & animation,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)767 bool AnimationExporter::checkIfSampledFloatIsAnimated ( const Animation & animation, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 768 { 769 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 770 771 if ( keyCount < 2 ) 772 return false; 773 774 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 775 776 float firstKeyValue; 777 778 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 779 { 780 float keyValue; 781 animation.getController()->GetValue(time, &keyValue, FOREVER, CTRL_ABSOLUTE); 782 783 if ( conversionFunctor ) 784 keyValue = (*conversionFunctor)(keyValue); 785 786 if ( time == startTime ) 787 firstKeyValue = keyValue; 788 else if ( !COLLADASW::MathUtils::equals(keyValue, firstKeyValue) ) 789 return true; 790 } 791 return false; 792 } 793 794 //--------------------------------------------------------------- checkIfSampledPoint3IsAnimated(const Animation & animation,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)795 bool AnimationExporter::checkIfSampledPoint3IsAnimated ( const Animation & animation, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 796 { 797 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 798 799 if ( keyCount < 2 ) 800 return false; 801 802 int keyLength = animation.getDimension(); 803 804 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 805 806 float firstFloatKeyValue; 807 Point3 firstKeyValue; 808 809 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 810 { 811 812 Point3 keyValue; 813 animation.getController()->GetValue(time, &keyValue, FOREVER, CTRL_ABSOLUTE); 814 815 816 if ( keyLength == 1) 817 { 818 float floatKeyValue = keyValue[ animation.getType() - Animation::POSITION_X ]; 819 820 if ( conversionFunctor ) 821 floatKeyValue = (*conversionFunctor)( floatKeyValue ); 822 823 if ( time == startTime ) 824 firstFloatKeyValue = floatKeyValue; 825 else if ( !COLLADASW::MathUtils::equals(floatKeyValue, firstFloatKeyValue) ) 826 return true; 827 828 } 829 else 830 { 831 for ( int j = 0; j < keyLength; ++j ) 832 { 833 assert( (keyLength == 3) || (keyLength == 4)); 834 835 if ( conversionFunctor ) 836 keyValue[j] = (*conversionFunctor) ( keyValue[ j ] ); 837 838 if ( time > startTime && !COLLADASW::MathUtils::equals(keyValue[j], firstKeyValue[j]) ) 839 return true; 840 } 841 842 if ( time == startTime ) 843 firstKeyValue = keyValue; 844 } 845 } 846 return false; 847 } 848 849 850 //--------------------------------------------------------------- checkIfSampledRotationIsAnimated(const Animation & animation,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)851 bool AnimationExporter::checkIfSampledRotationIsAnimated ( const Animation & animation, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 852 { 853 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 854 int keyLength = animation.getDimension(); 855 856 if ( keyCount < 2 ) 857 return false; 858 859 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 860 861 float firstFloatKeyValue; 862 float firstEulerAngles[ 3 ]; 863 864 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 865 { 866 867 float eulerAngles[ 3 ]; 868 869 if ( keyLength == 1 ) 870 { 871 Quat quaternion; 872 animation.getController()->GetValue(time, &quaternion, FOREVER, CTRL_ABSOLUTE); 873 QuatToEuler(quaternion, eulerAngles, EULERTYPE_XYZ); 874 } 875 else 876 { 877 AngAxis angleAxis; 878 animation.getController()->GetValue(time, &angleAxis, FOREVER, CTRL_ABSOLUTE); 879 Quat quaternion(angleAxis); 880 quaternion.GetEuler ( &eulerAngles[ 0 ], &eulerAngles[ 1 ], &eulerAngles[ 2 ] ); 881 } 882 883 if ( time > startTime) 884 patchEuler(mPreviousEulerAngles, eulerAngles); 885 886 mPreviousEulerAngles[0] = eulerAngles[0]; 887 mPreviousEulerAngles[1] = eulerAngles[1]; 888 mPreviousEulerAngles[2] = eulerAngles[2]; 889 890 if ( keyLength == 1) 891 { 892 float floatKeyValue = eulerAngles[ animation.getType() - Animation::ROTATION_X ]; 893 894 if ( conversionFunctor ) 895 floatKeyValue = (*conversionFunctor)(floatKeyValue); 896 897 if ( time == startTime ) 898 firstFloatKeyValue = floatKeyValue; 899 else if ( !COLLADASW::MathUtils::equals(floatKeyValue, firstFloatKeyValue) ) 900 return true; 901 } 902 else 903 { 904 for ( int j = 0; j < 3; ++j ) 905 { 906 if ( conversionFunctor ) 907 eulerAngles[j] = (*conversionFunctor) ( eulerAngles[ j ] ); 908 909 if ( time == startTime ) 910 firstEulerAngles[j] = eulerAngles[j]; 911 else if ( !COLLADASW::MathUtils::equals(eulerAngles[j], firstEulerAngles[j]) ) 912 return true; 913 } 914 } 915 } 916 return false; 917 } 918 919 920 checkIfSampledTransformationIsAnimated(const Animation & animation,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)921 bool AnimationExporter::checkIfSampledTransformationIsAnimated( const Animation & animation, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 922 { 923 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 924 int keyLength = animation.getDimension(); 925 926 if ( keyCount < 2 ) 927 return false; 928 929 INode * iNode = animation.getNode(); 930 931 Matrix3 transformationMatrix; 932 Matrix3 firstTransformationMatrix; 933 Matrix3 parentTransformationMatrix; 934 935 INode* parentINode = iNode->GetParentNode(); 936 937 if (parentINode && parentINode->IsRootNode()) 938 parentINode = 0; 939 940 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 941 { 942 // Export the base NODE TM 943 transformationMatrix = iNode->GetNodeTM(time); 944 945 if (parentINode) 946 { 947 // export a relative TM 948 // We have to use whatever value we exported for this parent 949 // in order to remain consistent in collada 950 parentTransformationMatrix = parentINode->GetNodeTM(time); 951 parentTransformationMatrix.Invert(); 952 transformationMatrix = transformationMatrix * parentTransformationMatrix; 953 } 954 955 const Matrix3& constTransformationMatrix = transformationMatrix; 956 957 if ( time == startTime ) 958 { 959 firstTransformationMatrix = transformationMatrix; 960 } 961 else 962 { 963 const Matrix3& constTransformationMatrix = transformationMatrix; 964 const Matrix3& constFirstTransformationMatrix = firstTransformationMatrix; 965 966 for ( int row = 0; row < 3; ++row) 967 for ( int col = 0; col < 4; ++col) 968 if ( !COLLADASW::MathUtils::equals(constTransformationMatrix[col][row], constFirstTransformationMatrix[col][row] ) ) 969 return true; 970 } 971 972 } 973 974 return false; 975 } 976 977 978 979 //--------------------------------------------------------------- getBaseId(const Animation & animation)980 String AnimationExporter::getBaseId ( const Animation & animation ) 981 { 982 983 String baseId = animation.getId(); 984 985 const String& sid = animation.getSid(); 986 987 if ( !sid.empty() ) 988 baseId += "_" + animation.getSid(); 989 990 991 if ( animation.getMatrixIndex() < 0) 992 { 993 if ( (animation.getDimension() == 1) && (animation.getParameter()) ) 994 baseId += "." + * ( animation.getParameter() ); 995 } 996 else 997 { 998 baseId += "_" + COLLADASW::Utils::toString(animation.getMatrixIndex()) + "_"; 999 } 1000 return baseId; 1001 } 1002 1003 //--------------------------------------------------------------- getTarget(const Animation & animation)1004 String AnimationExporter::getTarget ( const Animation & animation ) 1005 { 1006 String target = animation.getId(); 1007 1008 const String& sid = animation.getSid(); 1009 1010 if ( !sid.empty() ) 1011 target += "/" + animation.getSid(); 1012 1013 1014 if ( animation.getMatrixIndex() < 0) 1015 { 1016 if ( (animation.getDimension() == 1) && (animation.getParameter()) ) 1017 target += "." + * ( animation.getParameter() ); 1018 } 1019 else 1020 { 1021 target += "(" + COLLADASW::Utils::toString(animation.getMatrixIndex()) + ")"; 1022 } 1023 return target; 1024 } 1025 1026 //--------------------------------------------------------------- exportSources(Animation & animation)1027 void AnimationExporter::exportSources ( Animation & animation ) 1028 { 1029 Control * controller = animation.getController(); 1030 INode * iNode = animation.getNode(); 1031 1032 bool isSampling = !controller || mDocumentExporter->getOptions().getSampleAnimation(); 1033 1034 String baseId = getBaseId ( animation ); 1035 1036 IKeyControl * keyInterface = 0; 1037 1038 if (!isSampling) 1039 { 1040 keyInterface = GetKeyControlInterface ( controller ); 1041 if ( !keyInterface ) 1042 isSampling = true; 1043 else if (keyInterface->GetNumKeys() <= 1) 1044 return; 1045 } 1046 1047 1048 if ( !isSampling ) 1049 { 1050 Class_ID classId = controller->ClassID(); 1051 1052 if ( classId.PartB() != 0 ) 1053 { 1054 // This is not a Max controller, sample it. 1055 // The only max controllers that have non-zero 1056 // values are not keyable (attach, link, etc). 1057 isSampling = true; 1058 } 1059 else if ( keyInterface != NULL && keyInterface->GetNumKeys() > 0 ) 1060 { 1061 int keyCount = keyInterface->GetNumKeys(); 1062 1063 switch ( classId.PartA() ) 1064 { 1065 1066 case LININTERP_FLOAT_CLASS_ID: 1067 exportInputSource<ILinFloatKey> ( baseId, controller, keyInterface ); 1068 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getFloatValue<ILinFloatKey> ); 1069 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1070 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1071 break; 1072 1073 case LININTERP_POSITION_CLASS_ID: 1074 exportInputSource<ILinPoint3Key> ( baseId, controller, keyInterface ); 1075 1076 if ( animation.getDimension() == 1 ) 1077 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleValue<ILinPoint3Key> ); 1078 else 1079 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXValue<3, ILinPoint3Key> ); 1080 1081 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1082 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1083 break; 1084 1085 case LININTERP_ROTATION_CLASS_ID: 1086 exportInputSource<ILinRotKey> ( baseId, controller, keyInterface ); 1087 1088 if ( animation.getDimension() == 1 ) 1089 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleValue<ILinRotKey> ); 1090 else 1091 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationValue<ILinRotKey> ); 1092 1093 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1094 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1095 break; 1096 case LININTERP_SCALE_CLASS_ID: 1097 exportInputSource<ILinScaleKey> ( baseId, controller, keyInterface ); 1098 if ( animation.getType() == Animation::SCALE) 1099 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXValue<3, ILinScaleKey> ); 1100 else if ( animation.getType() == Animation::SCALE_ROT_AXIS ) 1101 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getScaleRotationAxisValue<ILinScaleKey, false> ); 1102 else if ( animation.getType() == Animation::SCALE_ROT_AXIS_R ) 1103 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getScaleRotationAxisValue<ILinScaleKey, true> ); 1104 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1105 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1106 break; 1107 case HYBRIDINTERP_FLOAT_CLASS_ID: 1108 exportInputSource<IBezFloatKey> ( baseId, controller, keyInterface ); 1109 1110 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getFloatValue<IBezFloatKey> ); 1111 1112 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getFloatInTangentValue ); 1113 1114 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getFloatOutTangentValue ); 1115 1116 exportInterpolationSource ( baseId, keyInterface, getBezierInterpolation<IBezFloatKey>, keyInterface->GetNumKeys() ); 1117 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::IN_TANGENT | Animation::OUT_TANGENT | Animation::INTERPOLATION); 1118 1119 break; 1120 case HYBRIDINTERP_POINT3_CLASS_ID: 1121 case HYBRIDINTERP_POSITION_CLASS_ID: 1122 case HYBRIDINTERP_COLOR_CLASS_ID: 1123 exportInputSource<IBezPoint3Key> ( baseId, controller, keyInterface ); 1124 if ( animation.getDimension() == 1 ) 1125 { 1126 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleValue<IBezPoint3Key> ); 1127 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleInTangentValue<IBezPoint3Key>); 1128 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleOutTangentValue<IBezPoint3Key> ); 1129 } 1130 else 1131 { 1132 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXValue<3, IBezPoint3Key> ); 1133 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXInTangentValue<3, IBezPoint3Key> ); 1134 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXOutTangentValue<3, IBezPoint3Key> ); 1135 } 1136 exportInterpolationSource ( baseId, keyInterface, getBezierInterpolation<IBezPoint3Key>, keyInterface->GetNumKeys() ); 1137 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::IN_TANGENT | Animation::OUT_TANGENT | Animation::INTERPOLATION); 1138 break; 1139 case HYBRIDINTERP_POINT4_CLASS_ID: 1140 case HYBRIDINTERP_FRGBA_CLASS_ID: 1141 exportInputSource<IBezPoint4Key> ( baseId, controller, keyInterface ); 1142 if ( animation.getDimension() == 1 ) 1143 { 1144 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleValue<IBezPoint4Key> ); 1145 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleInTangentValue<IBezPoint4Key> ); 1146 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXSingleOutTangentValue<IBezPoint4Key> ); 1147 } 1148 else 1149 { 1150 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXValue<4, IBezPoint4Key> ); 1151 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXInTangentValue<4, IBezPoint4Key> ); 1152 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXOutTangentValue<4, IBezPoint4Key> ); 1153 } 1154 exportInterpolationSource ( baseId, keyInterface, getBezierInterpolation<IBezPoint4Key>, keyInterface->GetNumKeys() ); 1155 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::IN_TANGENT | Animation::OUT_TANGENT | Animation::INTERPOLATION); 1156 break; 1157 1158 case HYBRIDINTERP_ROTATION_CLASS_ID: 1159 exportInputSource<IBezQuatKey> ( baseId, controller, keyInterface ); 1160 if ( animation.getDimension() == 1 ) 1161 { 1162 mKeyValueList.reserve( keyInterface->GetNumKeys() ); 1163 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleValuePatchEuler ); 1164 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleInTangentPatchEuler ); 1165 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleOutTangentPatchEuler ); 1166 } 1167 else 1168 { 1169 mKeyValueList.reserve( 3 * keyInterface->GetNumKeys() ); 1170 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationValuePatchEuler ); 1171 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleInTangentPatchEuler ); 1172 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getRotationSingleOutTangentPatchEuler ); 1173 } 1174 mKeyValueList.clear(); 1175 exportInterpolationSource ( baseId, keyInterface, getBezierInterpolation<IBezQuatKey>, keyInterface->GetNumKeys() ); 1176 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::IN_TANGENT | Animation::OUT_TANGENT | Animation::INTERPOLATION); 1177 break; 1178 case HYBRIDINTERP_SCALE_CLASS_ID: 1179 exportInputSource<IBezScaleKey> ( baseId, controller, keyInterface ); 1180 if ( animation.getType() == Animation::SCALE) 1181 { 1182 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXValue<3, IBezScaleKey> ); 1183 exportInTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXInTangentValue<3, IBezScaleKey> ); 1184 exportOutTangentSource ( animation, baseId, keyInterface, &AnimationExporter::getPointXOutTangentValue<3, IBezScaleKey> ); 1185 exportInterpolationSource ( baseId, keyInterface, getBezierInterpolation<IBezScaleKey>, keyInterface->GetNumKeys() ); 1186 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::IN_TANGENT | Animation::OUT_TANGENT | Animation::INTERPOLATION); 1187 } 1188 else if ( animation.getType() == Animation::SCALE_ROT_AXIS ) 1189 { 1190 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getScaleRotationAxisValue<IBezScaleKey, false> ); 1191 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1192 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1193 } 1194 else if ( animation.getType() == Animation::SCALE_ROT_AXIS_R ) 1195 { 1196 exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getScaleRotationAxisValue<IBezScaleKey, true> ); 1197 exportInterpolationSource ( baseId, keyInterface, getUniformInterpolation<LibraryAnimations::LINEAR_NAME>, keyInterface->GetNumKeys() ); 1198 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1199 } 1200 break; 1201 1202 // case TCBINTERP_FLOAT_CLASS_ID: 1203 // exportInputSource<ITCBFloatKey> ( baseId, controller, keyInterface ); 1204 // exportOutputSource ( animation, baseId, keyInterface, &AnimationExporter::getFloatValue<ITCBFloatKey> ); 1205 1206 break; 1207 default: 1208 isSampling = true; 1209 break; 1210 } 1211 } 1212 } 1213 1214 if ( isSampling ) 1215 { 1216 int ticksPerFrame = GetTicksPerFrame(); 1217 TimeValue startTime = mDocumentExporter->getOptions().getAnimationStart(); 1218 TimeValue endTime = mDocumentExporter->getOptions().getAnimationEnd() + 1; 1219 1220 if ( endTime > startTime ) 1221 { 1222 exportSamplingInputSource(baseId, startTime, endTime, ticksPerFrame); 1223 if ( controller ) 1224 { 1225 SClass_ID type = controller->SuperClassID(); 1226 switch (type) 1227 { 1228 case CTRL_FLOAT_CLASS_ID: 1229 exportSamplingFloatOutputSource(animation, baseId, keyInterface, startTime, endTime, ticksPerFrame); 1230 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1231 break; 1232 case CTRL_POINT3_CLASS_ID: 1233 case CTRL_POSITION_CLASS_ID: 1234 exportSamplingPoint3OutputSource(animation, baseId, keyInterface, startTime, endTime, ticksPerFrame); 1235 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1236 break; 1237 case CTRL_ROTATION_CLASS_ID: 1238 exportSamplingRotationOutputSource(animation, baseId, keyInterface, startTime, endTime, ticksPerFrame); 1239 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1240 break; 1241 } 1242 } 1243 else if ( iNode ) 1244 { 1245 exportSamplingTransformationOutputSource(animation, baseId, keyInterface, startTime, endTime, ticksPerFrame); 1246 animation.setInputTypeFlags(Animation::INPUT | Animation::OUTPUT | Animation::INTERPOLATION); 1247 } 1248 exportSamplingInterpolationSource(baseId, startTime, endTime, ticksPerFrame); 1249 } 1250 1251 } 1252 } 1253 1254 1255 //--------------------------------------------------------------- 1256 template <class KeyClassName> exportInputSource(const String & baseId,Control * controller,IKeyControl * keyInterface)1257 void AnimationExporter::exportInputSource ( const String & baseId, Control * controller, IKeyControl* keyInterface ) 1258 { 1259 int keyCount = keyInterface->GetNumKeys(); 1260 1261 COLLADASW::FloatSource source ( mSW ); 1262 source.setId ( baseId + INPUT_SOURCE_ID_SUFFIX ); 1263 source.setArrayId ( baseId + INPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 1264 source.setAccessorStride ( 1 ); 1265 source.getParameterNameList().push_back ( "TIME" ); 1266 source.setAccessorCount ( keyCount ); 1267 source.prepareToAppendValues(); 1268 1269 for ( int i = 0; i < keyCount; ++i ) 1270 { 1271 KeyClassName key; 1272 keyInterface->GetKey ( i, &key ); 1273 source.appendValues ( key.time * mTimeFactor ); 1274 } 1275 1276 source.finish(); 1277 } 1278 1279 1280 //--------------------------------------------------------------- exportOutputSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,OutputValueFunctionPtr outputValueFunction)1281 void AnimationExporter::exportOutputSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, OutputValueFunctionPtr outputValueFunction ) 1282 { 1283 int keyCount = keyInterface->GetNumKeys(); 1284 int keyLength = animation.getDimension(); 1285 1286 COLLADASW::FloatSource source ( mSW ); 1287 source.setId ( baseId + OUTPUT_SOURCE_ID_SUFFIX ); 1288 source.setArrayId ( baseId + OUTPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 1289 source.setAccessorStride ( keyLength ); 1290 1291 for ( int i = 0; i < keyLength; ++i ) 1292 { 1293 if ( animation.getParameter() ) 1294 source.getParameterNameList().push_back ( * ( animation.getParameter() + i) ); 1295 else 1296 source.getParameterNameList().push_back ( EMPTY_STRING ); 1297 } 1298 1299 source.setAccessorCount ( keyCount ); 1300 1301 source.prepareToAppendValues(); 1302 1303 float * keyBuffer = new float[ keyLength ]; 1304 1305 for ( int i = 0; i < keyCount; ++i ) 1306 { 1307 (this->*outputValueFunction) ( keyBuffer, keyInterface, i, animation ); 1308 1309 for ( int j = 0; j < keyLength; ++j ) 1310 { 1311 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 1312 1313 if ( conversionFunctor ) 1314 source.appendValues ( (*conversionFunctor) ( keyBuffer[ j ] ) ); 1315 else 1316 source.appendValues ( keyBuffer[ j ] ); 1317 } 1318 } 1319 1320 delete[] keyBuffer; 1321 1322 source.finish(); 1323 } 1324 1325 //--------------------------------------------------------------- 1326 template <class KeyType> getFloatValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1327 void AnimationExporter::getFloatValue ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1328 { 1329 KeyType key; 1330 keyInterface->GetKey ( keyIndex, &key ); 1331 *keyValues = key.val; 1332 } 1333 1334 //--------------------------------------------------------------- 1335 template<class KeyType> getPointXSingleValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1336 void AnimationExporter::getPointXSingleValue ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1337 { 1338 KeyType key; 1339 keyInterface->GetKey ( keyIndex, &key ); 1340 *keyValues = key.val[ animation.getType() - Animation::POSITION_X ]; 1341 } 1342 1343 //--------------------------------------------------------------- 1344 template<int dimension, class KeyType> getPointXValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1345 void AnimationExporter::getPointXValue ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1346 { 1347 KeyType key; 1348 keyInterface->GetKey ( keyIndex, &key ); 1349 for ( int i = 0; i<dimension; ++i) 1350 keyValues[ i ] = key.val[ i ]; 1351 } 1352 1353 //--------------------------------------------------------------- 1354 template<class KeyType> getRotationSingleValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1355 void AnimationExporter::getRotationSingleValue ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1356 { 1357 KeyType key; 1358 keyInterface->GetKey ( keyIndex, &key ); 1359 float eulerAngles[ 3 ]; 1360 key.val.GetEuler ( &eulerAngles[ 0 ], &eulerAngles[ 1 ], &eulerAngles[ 2 ] ); 1361 *keyValues = eulerAngles[ animation.getType() - Animation::ROTATION_X ]; 1362 } 1363 1364 //--------------------------------------------------------------- 1365 template<class KeyType> getRotationValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1366 void AnimationExporter::getRotationValue ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1367 { 1368 KeyType key; 1369 keyInterface->GetKey ( keyIndex, &key ); 1370 key.val.GetEuler ( &keyValues[ 0 ], &keyValues[ 1 ], &keyValues[ 2 ] ); 1371 } 1372 1373 1374 //--------------------------------------------------------------- getRotationSingleValuePatchEuler(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1375 void AnimationExporter::getRotationSingleValuePatchEuler ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1376 { 1377 IBezQuatKey key; 1378 keyInterface->GetKey ( keyIndex, &key ); 1379 float eulerAngles[ 3 ]; 1380 key.val.GetEuler ( &eulerAngles[ 0 ], &eulerAngles[ 1 ], &eulerAngles[ 2 ] ); 1381 if ( keyIndex > 0) 1382 patchEuler(mPreviousEulerAngles, eulerAngles); 1383 1384 mPreviousEulerAngles[0] = eulerAngles[0]; 1385 mPreviousEulerAngles[1] = eulerAngles[1]; 1386 mPreviousEulerAngles[2] = eulerAngles[2]; 1387 1388 *keyValues = eulerAngles[ animation.getType() - Animation::ROTATION_X ]; 1389 1390 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 1391 if ( conversionFunctor ) 1392 mKeyValueList.push_back((float)((*conversionFunctor)(*keyValues))); 1393 else 1394 mKeyValueList.push_back((float)(*keyValues)); 1395 1396 } 1397 1398 //--------------------------------------------------------------- getRotationValuePatchEuler(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1399 void AnimationExporter::getRotationValuePatchEuler ( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1400 { 1401 IBezQuatKey key; 1402 keyInterface->GetKey ( keyIndex, &key ); 1403 float eulerAngles[ 3 ]; 1404 key.val.GetEuler ( &eulerAngles[ 0 ], &eulerAngles[ 1 ], &eulerAngles[ 2 ] ); 1405 if ( keyIndex > 0) 1406 patchEuler(mPreviousEulerAngles, eulerAngles); 1407 1408 mPreviousEulerAngles[0] = eulerAngles[0]; 1409 mPreviousEulerAngles[1] = eulerAngles[1]; 1410 mPreviousEulerAngles[2] = eulerAngles[2]; 1411 1412 keyValues[ 0 ] = eulerAngles[0]; 1413 keyValues[ 1 ] = eulerAngles[1]; 1414 keyValues[ 2 ] = eulerAngles[2]; 1415 1416 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 1417 if ( conversionFunctor ) 1418 { 1419 mKeyValueList.push_back((float)((*conversionFunctor)(eulerAngles[0]))); 1420 mKeyValueList.push_back((float)((*conversionFunctor)(eulerAngles[1]))); 1421 mKeyValueList.push_back((float)((*conversionFunctor)(eulerAngles[2]))); 1422 } 1423 else 1424 { 1425 mKeyValueList.push_back(eulerAngles[0]); 1426 mKeyValueList.push_back(eulerAngles[1]); 1427 mKeyValueList.push_back(eulerAngles[2]); 1428 } 1429 } 1430 1431 1432 //--------------------------------------------------------------- 1433 template<class KeyType, bool reversed> getScaleRotationAxisValue(float * keyValues,IKeyControl * keyInterface,const int & keyIndex,const Animation & animation)1434 void AnimationExporter::getScaleRotationAxisValue( float * keyValues, IKeyControl * keyInterface, const int & keyIndex, const Animation & animation ) 1435 { 1436 KeyType key; 1437 keyInterface->GetKey ( keyIndex, &key ); 1438 AngAxis angleAxis(key.val.q); 1439 1440 keyValues[0] = angleAxis.axis.x; 1441 keyValues[1] = angleAxis.axis.y; 1442 keyValues[2] = angleAxis.axis.z; 1443 if ( reversed ) 1444 keyValues[3] = -COLLADASW::MathUtils::radToDegF(angleAxis.angle); 1445 else 1446 keyValues[3] = COLLADASW::MathUtils::radToDegF(angleAxis.angle); 1447 } 1448 1449 1450 //--------------------------------------------------------------- exportTangentSource(const String & sourceIdSuffix,const Animation & animation,const String & baseId,IKeyControl * keyInterface,TangentValueFunctionPtr tangentValueFunction)1451 void AnimationExporter::exportTangentSource ( const String & sourceIdSuffix, const Animation & animation, const String & baseId, IKeyControl* keyInterface, TangentValueFunctionPtr tangentValueFunction ) 1452 { 1453 int keyCount = keyInterface->GetNumKeys(); 1454 int keyLength = animation.getDimension(); 1455 1456 COLLADASW::FloatSource source ( mSW ); 1457 source.setId ( baseId + sourceIdSuffix ); 1458 source.setArrayId ( baseId + sourceIdSuffix + ARRAY_ID_SUFFIX ); 1459 source.setAccessorStride ( 2 * keyLength ); 1460 for ( int i = 0; i < keyLength; ++i ) 1461 { 1462 source.getParameterNameList().push_back ( "X" ); 1463 source.getParameterNameList().push_back ( "Y" ); 1464 } 1465 source.setAccessorCount ( keyCount ); 1466 source.prepareToAppendValues(); 1467 1468 float * keyBufferX = new float[ keyLength ]; 1469 float * keyBufferY = new float[ keyLength ]; 1470 1471 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 1472 1473 for ( int i = 0; i < keyCount; ++i ) 1474 { 1475 ( this->*tangentValueFunction ) ( keyBufferX, keyBufferY, keyInterface, i, keyCount, animation ); 1476 for ( int j = 0; j < keyLength; ++j ) 1477 { 1478 if ( conversionFunctor ) 1479 source.appendValues ( keyBufferX[j], (*conversionFunctor)(keyBufferY[j]) ); 1480 else 1481 source.appendValues ( keyBufferX[j], keyBufferY[j] ); 1482 } 1483 } 1484 1485 delete[] keyBufferX; 1486 delete[] keyBufferY; 1487 1488 source.finish(); 1489 } 1490 1491 //--------------------------------------------------------------- exportInTangentSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TangentValueFunctionPtr tangentValueFunction)1492 void AnimationExporter::exportInTangentSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TangentValueFunctionPtr tangentValueFunction ) 1493 { 1494 exportTangentSource ( INTANGENT_SOURCE_ID_SUFFIX, animation, baseId, keyInterface, tangentValueFunction ); 1495 } 1496 1497 //--------------------------------------------------------------- getFloatInTangentValue(float * inTangentValuesX,float * inTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1498 void AnimationExporter::getFloatInTangentValue ( float * inTangentValuesX, float * inTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1499 { 1500 IBezFloatKey key; 1501 keyInterface->GetKey ( keyIndex, &key ); 1502 1503 float previousTime = ( float ) getPreviousTime ( keyIndex, animation.getController() ); 1504 1505 //testing 1506 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1507 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1508 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1509 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1510 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1511 */ 1512 InterpolationType interpolationInType = getInterpolationInType ( key.flags ); 1513 1514 // export control point. If it is not a BEZIER interpolation, export the point itself 1515 1516 if ( interpolationInType == BEZIER ) 1517 { 1518 if ( GetInTanType ( key.flags ) != BEZKEY_USER ) 1519 key.inLength = DEFAULT_INLENGHT_FLOAT; 1520 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1521 key.inLength *= GetTicksPerFrame() / ( float ) ( key.time - previousTime ); 1522 1523 float inInterval = ( key.time - previousTime ) * key.inLength; 1524 1525 *inTangentValuesX = ( key.time - inInterval ) * mTimeFactor; 1526 1527 *inTangentValuesY = key.val + key.intan * inInterval; 1528 } 1529 else if ( interpolationInType == LINEAR ) 1530 { 1531 *inTangentValuesX = (key.time - ( key.time - previousTime )/3) * mTimeFactor; 1532 // get the previous key value 1533 int numKeys = keyInterface->GetNumKeys(); 1534 int previousKeyIndex = ( keyIndex > 0 ) ? keyIndex - 1 : numKeys - 1; 1535 IBezFloatKey previousKey; 1536 keyInterface->GetKey ( previousKeyIndex, &previousKey ); 1537 *inTangentValuesY = (key.val - ( key.val - previousKey.val )/3); 1538 } 1539 else 1540 { 1541 /// @TODO: clarify if this makes sense or if we should export the same as above 1542 *inTangentValuesX = key.time * mTimeFactor; 1543 *inTangentValuesY = key.val; 1544 } 1545 } 1546 1547 1548 //--------------------------------------------------------------- 1549 template <class KeyType> getPointXSingleInTangentValue(float * inTangentValuesX,float * inTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1550 void AnimationExporter::getPointXSingleInTangentValue ( float * inTangentValuesX, float * inTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1551 { 1552 KeyType key; 1553 keyInterface->GetKey ( keyIndex, &key ); 1554 1555 float previousTime = ( float ) getPreviousTime ( keyIndex, animation.getController() ); 1556 1557 //testing 1558 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1559 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1560 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1561 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1562 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1563 */ 1564 InterpolationType interpolationInType = getInterpolationInType ( key.flags ); 1565 1566 int keyParamterIndex = animation.getType() - Animation::POSITION_X; 1567 1568 // export control point. If it is not a BEZIER interpolation, export the point itself 1569 1570 if ( interpolationInType == BEZIER ) 1571 { 1572 if ( GetInTanType ( key.flags ) != BEZKEY_USER ) 1573 key.inLength = DEFAULT_INLENGHT_POINTX_FLOAT_ARRAY; 1574 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1575 key.inLength *= GetTicksPerFrame() / ( float ) ( key.time - previousTime ); 1576 1577 float inInterval = ( key.time - previousTime ) * key.inLength[keyParamterIndex]; 1578 *inTangentValuesX = ( key.time - inInterval ) * mTimeFactor; 1579 *inTangentValuesY = key.val[keyParamterIndex] + key.intan[keyParamterIndex] * inInterval; 1580 } 1581 else if ( interpolationInType == LINEAR ) 1582 { 1583 *inTangentValuesX = (key.time - ( key.time - previousTime )/3) * mTimeFactor; 1584 // get the previous key value 1585 int numKeys = keyInterface->GetNumKeys(); 1586 int previousKeyIndex = ( keyIndex > 0 ) ? keyIndex - 1 : numKeys - 1; 1587 KeyType previousKey; 1588 keyInterface->GetKey( previousKeyIndex, &previousKey ); 1589 *inTangentValuesY = (key.val[keyParamterIndex] - ( key.val[keyParamterIndex] - previousKey.val[keyParamterIndex] )/3); 1590 } 1591 else 1592 { 1593 /// @TODO: clarify if this makes sense or if we should export the same as above 1594 *inTangentValuesX = key.time * mTimeFactor; 1595 *inTangentValuesY = key.val[keyParamterIndex]; 1596 } 1597 } 1598 1599 1600 //--------------------------------------------------------------- 1601 template <int dimension, class KeyType> getPointXInTangentValue(float * inTangentValuesX,float * inTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1602 void AnimationExporter::getPointXInTangentValue ( float * inTangentValuesX, float * inTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1603 { 1604 KeyType key; 1605 keyInterface->GetKey ( keyIndex, &key ); 1606 1607 float previousTime = ( float ) getPreviousTime ( keyIndex, animation.getController() ); 1608 1609 //testing 1610 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1611 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1612 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1613 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1614 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1615 */ 1616 InterpolationType interpolationInType = getInterpolationInType ( key.flags ); 1617 1618 // export control point. If it is not a BEZIER interpolation, export the point itself 1619 1620 if ( interpolationInType == BEZIER ) 1621 { 1622 if ( GetInTanType ( key.flags ) != BEZKEY_USER ) 1623 key.inLength = DEFAULT_INLENGHT_POINTX_FLOAT_ARRAY; 1624 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1625 key.inLength *= GetTicksPerFrame() / ( float ) ( key.time - previousTime ); 1626 1627 float inInterval; 1628 1629 for ( int i = 0; i<dimension; ++i) 1630 { 1631 inInterval = ( key.time - previousTime ) * key.inLength[i]; 1632 inTangentValuesX[i] = ( key.time - inInterval ) * mTimeFactor; 1633 inTangentValuesY[i] = key.val[i] + key.intan[i] * inInterval; 1634 } 1635 1636 } 1637 else if ( interpolationInType == LINEAR ) 1638 { 1639 float inTangentX = (key.time - ( key.time - previousTime )/3) * mTimeFactor; 1640 1641 // get the previous key value 1642 int numKeys = keyInterface->GetNumKeys(); 1643 int previousKeyIndex = ( keyIndex > 0 ) ? keyIndex - 1 : numKeys - 1; 1644 KeyType previousKey; 1645 keyInterface->GetKey ( previousKeyIndex, &previousKey ); 1646 1647 for ( int i = 0; i<dimension; ++i) 1648 { 1649 inTangentValuesX[i] = inTangentX; 1650 inTangentValuesY[i] = (key.val[i] - ( key.val[i] - previousKey.val[i] )/3); 1651 } 1652 } 1653 else 1654 { 1655 /// @TODO: clarify if this makes sense or if we should export the same as above 1656 for ( int i = 0; i<dimension; ++i) 1657 { 1658 inTangentValuesX[i] = key.time * mTimeFactor; 1659 inTangentValuesY[i] = key.val[i]; 1660 } 1661 } 1662 } 1663 1664 1665 //--------------------------------------------------------------- getRotationSingleInTangentPatchEuler(float * inTangentValuesX,float * inTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1666 void AnimationExporter::getRotationSingleInTangentPatchEuler ( float * inTangentValuesX, float * inTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1667 { 1668 IBezQuatKey key; 1669 keyInterface->GetKey ( keyIndex, &key ); 1670 1671 float previousTime = ( float ) getPreviousTime ( keyIndex, animation.getController() ); 1672 1673 //testing 1674 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1675 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1676 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1677 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1678 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1679 */ 1680 InterpolationType interpolationInType = getInterpolationInType ( key.flags ); 1681 1682 int keyParamterIndex = animation.getType() - Animation::ROTATION_X; 1683 1684 1685 // export control point. If it is not a BEZIER interpolation, export the point itself 1686 1687 size_t keyValueIndex = keyIndex; 1688 1689 if ( interpolationInType == BEZIER ) 1690 { 1691 float inInterval = ( key.time - previousTime ) * DEFAULT_INLENGHT; 1692 *inTangentValuesX = ( key.time - inInterval ) * mTimeFactor; 1693 *inTangentValuesY = mKeyValueList[keyValueIndex]; 1694 } 1695 else if ( interpolationInType == LINEAR ) 1696 { 1697 *inTangentValuesX = (key.time - ( key.time - previousTime )/3) * mTimeFactor; 1698 // get the previous key value 1699 size_t numKeys = mKeyValueList.size(); 1700 size_t previousKeyIndex = ( keyValueIndex > 0 ) ? keyValueIndex - 1 : numKeys - 1; 1701 *inTangentValuesY = (mKeyValueList[keyValueIndex] - ( mKeyValueList[keyValueIndex] - mKeyValueList[previousKeyIndex] )/3); 1702 } 1703 else 1704 { 1705 /// @TODO: clarify if this makes sense or if we should export the same as above 1706 *inTangentValuesX = key.time * mTimeFactor; 1707 1708 *inTangentValuesY = mKeyValueList[keyValueIndex]; 1709 } 1710 } 1711 1712 1713 //--------------------------------------------------------------- getRotationInTangentPatchEuler(float * inTangentValuesX,float * inTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1714 void AnimationExporter::getRotationInTangentPatchEuler ( float * inTangentValuesX, float * inTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1715 { 1716 IBezQuatKey key; 1717 keyInterface->GetKey ( keyIndex, &key ); 1718 1719 float previousTime = ( float ) getPreviousTime ( keyIndex, animation.getController() ); 1720 1721 //testing 1722 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1723 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1724 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1725 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1726 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1727 */ 1728 InterpolationType interpolationInType = getInterpolationInType ( key.flags ); 1729 1730 // export control point. If it is not a BEZIER interpolation, export the point itself 1731 1732 size_t keyValueIndex = 3 * keyIndex; 1733 1734 if ( interpolationInType == BEZIER ) 1735 { 1736 float inInterval = ( key.time - previousTime ) * DEFAULT_INLENGHT; 1737 1738 inTangentValuesX[0] = ( key.time - inInterval ) * mTimeFactor; 1739 inTangentValuesY[0] = mKeyValueList[keyValueIndex++]; 1740 1741 inTangentValuesX[1] = inTangentValuesX[0]; 1742 inTangentValuesY[1] = mKeyValueList[keyValueIndex++]; 1743 1744 inTangentValuesX[2] = inTangentValuesX[0]; 1745 inTangentValuesY[2] = mKeyValueList[keyValueIndex++]; 1746 } 1747 else if ( interpolationInType == LINEAR ) 1748 { 1749 size_t numKeys = mKeyValueList.size(); 1750 1751 float inTangentX = (key.time - ( key.time - previousTime )/3) * mTimeFactor; 1752 1753 for ( size_t i = 0; i < 3; ++i, keyValueIndex++) 1754 { 1755 inTangentValuesX[i] = inTangentX; 1756 // get the previous key value 1757 size_t previousKeyIndex = ( keyValueIndex > 0 ) ? keyValueIndex - 1 : numKeys - 1; 1758 inTangentValuesY[i] = (mKeyValueList[keyValueIndex] - ( mKeyValueList[keyValueIndex] - mKeyValueList[previousKeyIndex] )/3); 1759 } 1760 } 1761 else 1762 { 1763 /// @TODO: clarify if this makes sense or if we should export the same as above 1764 inTangentValuesX[0] = key.time * mTimeFactor; 1765 inTangentValuesX[1] = inTangentValuesX[0]; 1766 inTangentValuesX[2] = inTangentValuesX[0]; 1767 1768 inTangentValuesY[0] = mKeyValueList[keyValueIndex++]; 1769 inTangentValuesY[1] = mKeyValueList[keyValueIndex++]; 1770 inTangentValuesY[2] = mKeyValueList[keyValueIndex++]; 1771 } 1772 } 1773 1774 1775 //--------------------------------------------------------------- exportOutTangentSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TangentValueFunctionPtr tangentValueFunction)1776 void AnimationExporter::exportOutTangentSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TangentValueFunctionPtr tangentValueFunction ) 1777 { 1778 exportTangentSource ( OUTTANGENT_SOURCE_ID_SUFFIX, animation, baseId, keyInterface, tangentValueFunction ); 1779 } 1780 1781 //--------------------------------------------------------------- getFloatOutTangentValue(float * outTangentValuesX,float * outTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1782 void AnimationExporter::getFloatOutTangentValue ( float * outTangentValuesX, float * outTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1783 { 1784 IBezFloatKey key; 1785 keyInterface->GetKey ( keyIndex, &key ); 1786 1787 float nextTime = ( float ) getNextTime ( keyIndex, keyCount, animation.getController() ); 1788 1789 //testing 1790 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1791 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1792 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1793 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1794 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1795 */ 1796 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 1797 1798 // export control point. If it is not a BEZIER interpolation, export the point itself 1799 1800 if ( interpolationOutType == BEZIER ) 1801 { 1802 if ( GetOutTanType ( key.flags ) != BEZKEY_USER ) 1803 key.outLength = DEFAULT_OUTLENGHT_FLOAT; 1804 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1805 key.outLength *= GetTicksPerFrame() / ( float ) ( nextTime - key.time ); 1806 1807 float outInterval = ( nextTime - key.time ) * key.outLength; 1808 1809 *outTangentValuesX = ( key.time + outInterval ) * mTimeFactor; 1810 1811 *outTangentValuesY = key.val + key.outtan * outInterval; 1812 } 1813 else if ( interpolationOutType == LINEAR ) 1814 { 1815 *outTangentValuesX = (key.time + ( nextTime - key.time )/3) * mTimeFactor; 1816 // get the next key value 1817 int numKeys = keyInterface->GetNumKeys(); 1818 int nextKeyIndex = (keyIndex + 1 < numKeys ) ? keyIndex + 1 : 0; 1819 IBezFloatKey nextKey; 1820 keyInterface->GetKey ( nextKeyIndex, &nextKey ); 1821 *outTangentValuesY = (key.val + ( nextKey.val - key.val )/3); 1822 } 1823 else 1824 { 1825 *outTangentValuesX = key.time * mTimeFactor; 1826 *outTangentValuesY = key.val; 1827 } 1828 } 1829 1830 1831 //--------------------------------------------------------------- 1832 template <class KeyType> getPointXSingleOutTangentValue(float * outTangentValuesX,float * outTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1833 void AnimationExporter::getPointXSingleOutTangentValue ( float * outTangentValuesX, float * outTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1834 { 1835 KeyType key; 1836 keyInterface->GetKey ( keyIndex, &key ); 1837 1838 float nextTime = ( float ) getNextTime ( keyIndex, keyCount, animation.getController() ); 1839 1840 //testing 1841 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1842 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1843 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1844 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1845 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1846 */ 1847 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 1848 1849 int keyParamterIndex = animation.getType() - Animation::POSITION_X; 1850 1851 // export control point. If it is not a BEZIER interpolation, export the point itself 1852 1853 if ( interpolationOutType == BEZIER ) 1854 { 1855 1856 if ( GetOutTanType ( key.flags ) != BEZKEY_USER ) 1857 key.outLength = DEFAULT_OUTLENGHT_POINTX_FLOAT_ARRAY; 1858 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1859 key.outLength *= GetTicksPerFrame() / ( float ) ( nextTime - key.time ); 1860 1861 float outInterval = ( nextTime - key.time ) * key.outLength[keyParamterIndex]; 1862 1863 *outTangentValuesX = ( key.time + outInterval ) * mTimeFactor; 1864 *outTangentValuesY = key.val[keyParamterIndex] + key.outtan[keyParamterIndex] * outInterval; 1865 } 1866 else if ( interpolationOutType == LINEAR ) 1867 { 1868 *outTangentValuesX = (key.time + ( nextTime - key.time )/3) * mTimeFactor; 1869 // get the next key value 1870 int numKeys = keyInterface->GetNumKeys(); 1871 int nextKeyIndex = (keyIndex + 1 < numKeys ) ? keyIndex + 1 : 0; 1872 KeyType nextKey; 1873 keyInterface->GetKey ( nextKeyIndex, &nextKey ); 1874 *outTangentValuesY = (key.val[keyParamterIndex] + ( nextKey.val[keyParamterIndex] - key.val[keyParamterIndex] )/3); 1875 } 1876 else 1877 { 1878 /// @TODO: clarify if this makes sense or if we should export the same as above 1879 *outTangentValuesX = key.time * mTimeFactor; 1880 *outTangentValuesY = key.val[keyParamterIndex]; 1881 } 1882 } 1883 1884 1885 //--------------------------------------------------------------- 1886 template <int dimension, class KeyType> getPointXOutTangentValue(float * outTangentValuesX,float * outTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1887 void AnimationExporter::getPointXOutTangentValue ( float * outTangentValuesX, float * outTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1888 { 1889 KeyType key; 1890 keyInterface->GetKey ( keyIndex, &key ); 1891 1892 float nextTime = ( float ) getNextTime ( keyIndex, keyCount, animation.getController() ); 1893 1894 //testing 1895 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1896 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1897 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1898 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1899 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1900 */ 1901 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 1902 1903 // export control point. If it is not a BEZIER interpolation, export the point itself 1904 1905 if ( interpolationOutType == BEZIER ) 1906 { 1907 if ( GetOutTanType ( key.flags ) != BEZKEY_USER ) 1908 key.outLength = DEFAULT_OUTLENGHT_POINTX_FLOAT_ARRAY; 1909 else if ( key.flags & BEZKEY_UNCONSTRAINHANDLE ) 1910 key.outLength *= GetTicksPerFrame() / ( float ) ( nextTime - key.time ); 1911 1912 float outInterval; 1913 1914 for ( int i = 0; i<dimension; ++i) 1915 { 1916 outInterval = ( nextTime - key.time ) * key.outLength[i]; 1917 outTangentValuesX[i] = ( key.time + outInterval ) * mTimeFactor; 1918 outTangentValuesY[i] = key.val[i] + key.outtan[i] * outInterval; 1919 } 1920 } 1921 else if ( interpolationOutType == LINEAR ) 1922 { 1923 float outTangentX = (key.time + ( nextTime - key.time )/3) * mTimeFactor; 1924 // get the next key value 1925 int numKeys = keyInterface->GetNumKeys(); 1926 int nextKeyIndex = (keyIndex + 1 < numKeys ) ? keyIndex + 1 : 0; 1927 KeyType nextKey; 1928 keyInterface->GetKey ( nextKeyIndex, &nextKey ); 1929 1930 for ( int i = 0; i<dimension; ++i) 1931 { 1932 outTangentValuesX[i] = outTangentX; 1933 outTangentValuesY[i] = (key.val[i] + ( nextKey.val[i] - key.val[i] )/3); 1934 } 1935 } 1936 else 1937 { 1938 /// @TODO: clarify if this makes sense or if we should export the same as above 1939 for ( int i = 0; i<dimension; ++i) 1940 { 1941 outTangentValuesX[i] = key.time * mTimeFactor; 1942 outTangentValuesY[i] = key.val[i]; 1943 } 1944 } 1945 } 1946 1947 1948 //--------------------------------------------------------------- getRotationSingleOutTangentPatchEuler(float * outTangentValuesX,float * outTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1949 void AnimationExporter::getRotationSingleOutTangentPatchEuler ( float * outTangentValuesX, float * outTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1950 { 1951 IBezQuatKey key; 1952 keyInterface->GetKey ( keyIndex, &key ); 1953 1954 float nextTime = ( float ) getNextTime ( keyIndex, keyCount, animation.getController() ); 1955 1956 //testing 1957 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 1958 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 1959 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 1960 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 1961 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 1962 */ 1963 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 1964 1965 int keyParamterIndex = animation.getType() - Animation::ROTATION_X; 1966 1967 1968 // export control point. If it is not a BEZIER interpolation, export the point itself 1969 1970 size_t keyValueIndex = keyIndex; 1971 1972 if ( interpolationOutType == BEZIER ) 1973 { 1974 float outInterval = ( nextTime - key.time ) * DEFAULT_INLENGHT; 1975 *outTangentValuesX = ( key.time + outInterval ) * mTimeFactor; 1976 *outTangentValuesY = mKeyValueList[keyValueIndex]; 1977 } 1978 else if ( interpolationOutType == LINEAR ) 1979 { 1980 *outTangentValuesX = (key.time + ( nextTime - key.time )/3) * mTimeFactor; 1981 // get the next key value 1982 int numKeys = (int)mKeyValueList.size(); 1983 int nextKeyIndex = (keyIndex + 1 < numKeys ) ? keyIndex + 1 : 0; 1984 *outTangentValuesY = (mKeyValueList[keyValueIndex] + ( mKeyValueList[nextKeyIndex] - mKeyValueList[keyValueIndex] )/3); 1985 } 1986 else 1987 { 1988 /// @TODO: clarify if this makes sense or if we should export the same as above 1989 *outTangentValuesX = key.time * mTimeFactor; 1990 1991 *outTangentValuesY = mKeyValueList[keyValueIndex]; 1992 } 1993 } 1994 1995 1996 //--------------------------------------------------------------- getRotationOutTangentPatchEuler(float * outTangentValuesX,float * outTangentValuesY,IKeyControl * keyInterface,const int & keyIndex,const int & keyCount,const Animation & animation)1997 void AnimationExporter::getRotationOutTangentPatchEuler ( float * outTangentValuesX, float * outTangentValuesY, IKeyControl * keyInterface, const int & keyIndex, const int & keyCount, const Animation & animation ) 1998 { 1999 IBezQuatKey key; 2000 keyInterface->GetKey ( keyIndex, &key ); 2001 2002 float nextTime = ( float ) getNextTime ( keyIndex, keyCount, animation.getController() ); 2003 2004 //testing 2005 /* bool b1 = key.flags & BEZKEY_UNCONSTRAINHANDLE; 2006 bool b2 = GetInTanType( key.flags ) != BEZKEY_USER; 2007 bool b3 = GetOutTanType( key.flags ) != BEZKEY_USER; 2008 bool b4 = GetOutTanType( key.flags ) == BEZKEY_LINEAR; 2009 bool b5 = GetOutTanType( key.flags ) == BEZKEY_STEP; 2010 */ 2011 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 2012 2013 // export control point. If it is not a BEZIER interpolation, export the point itself 2014 2015 size_t keyValueIndex = 3 * keyIndex; 2016 2017 if ( interpolationOutType == BEZIER ) 2018 { 2019 float outInterval = ( nextTime - key.time ) * DEFAULT_INLENGHT; 2020 2021 outTangentValuesX[0] = ( key.time + outInterval ) * mTimeFactor; 2022 outTangentValuesY[0] = mKeyValueList[keyValueIndex++]; 2023 2024 outTangentValuesX[1] = outTangentValuesX[0]; 2025 outTangentValuesY[1] = mKeyValueList[keyValueIndex++]; 2026 2027 outTangentValuesX[2] = outTangentValuesX[0]; 2028 outTangentValuesY[2] = mKeyValueList[keyValueIndex++]; 2029 } 2030 else if ( interpolationOutType == LINEAR ) 2031 { 2032 int numKeys = (int)mKeyValueList.size(); 2033 2034 float outTangentX = (key.time + ( nextTime - key.time )/3) * mTimeFactor; 2035 2036 for ( size_t i = 0; i < 3; ++i, keyValueIndex++) 2037 { 2038 outTangentValuesX[i] = outTangentX; 2039 // get the next key value 2040 int nextKeyIndex = (keyIndex + 1 < numKeys ) ? keyIndex + 1 : 0; 2041 outTangentValuesY[i] = (mKeyValueList[keyValueIndex] + ( mKeyValueList[nextKeyIndex] - mKeyValueList[keyValueIndex] )/3); 2042 } 2043 } 2044 else 2045 { 2046 /// @TODO: clarify if this makes sense or if we should export the same as above 2047 outTangentValuesX[0] = key.time * mTimeFactor; 2048 outTangentValuesX[1] = outTangentValuesX[0]; 2049 outTangentValuesX[2] = outTangentValuesX[0]; 2050 2051 outTangentValuesY[0] = mKeyValueList[keyValueIndex++]; 2052 outTangentValuesY[1] = mKeyValueList[keyValueIndex++]; 2053 outTangentValuesY[2] = mKeyValueList[keyValueIndex++]; 2054 } 2055 } 2056 2057 2058 //--------------------------------------------------------------- getInterpolationInType(const DWORD & flags)2059 AnimationExporter::InterpolationType AnimationExporter::getInterpolationInType ( const DWORD & flags ) 2060 { 2061 switch ( GetInTanType ( flags ) ) 2062 { 2063 case BEZKEY_LINEAR: 2064 return LINEAR; 2065 case BEZKEY_STEP: 2066 return STEP; 2067 default: 2068 return BEZIER; 2069 } 2070 } 2071 2072 //--------------------------------------------------------------- getInterpolationOutType(const DWORD & flags)2073 AnimationExporter::InterpolationType AnimationExporter::getInterpolationOutType ( const DWORD & flags ) 2074 { 2075 switch ( GetOutTanType ( flags ) ) 2076 { 2077 case BEZKEY_LINEAR: 2078 return LINEAR; 2079 case BEZKEY_STEP: 2080 return STEP; 2081 default: 2082 return BEZIER; 2083 } 2084 } 2085 2086 //--------------------------------------------------------------- exportInterpolationSource(const String & baseId,IKeyControl * keyInterface,InterpolationTypeFunctionPtr interpolationTypeFunction,int keyCount)2087 void AnimationExporter::exportInterpolationSource ( const String & baseId, IKeyControl * keyInterface, InterpolationTypeFunctionPtr interpolationTypeFunction, int keyCount ) 2088 { 2089 COLLADASW::NameSource source ( mSW ); 2090 source.setId ( baseId + INTERPOLATION_SOURCE_ID_SUFFIX ); 2091 source.setArrayId ( baseId + INTERPOLATION_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2092 source.setAccessorStride ( 1 ); 2093 source.getParameterNameList().push_back ( "INTERPOLATION" ); 2094 source.setAccessorCount ( keyCount ); 2095 source.prepareToAppendValues(); 2096 2097 for ( int i = 0; i < keyCount; ++i ) 2098 source.appendValues ( interpolationTypeFunction ( keyInterface, i ) ); 2099 2100 source.finish(); 2101 } 2102 2103 //--------------------------------------------------------------- 2104 template <const String & interpolationTypeName> getUniformInterpolation(IKeyControl * keyInterface,int keyIndex)2105 const String & AnimationExporter::getUniformInterpolation ( IKeyControl * keyInterface, int keyIndex ) 2106 { 2107 return interpolationTypeName; 2108 } 2109 2110 //--------------------------------------------------------------- 2111 template <class KeyType> getBezierInterpolation(IKeyControl * keyInterface,int keyIndex)2112 const String & AnimationExporter::getBezierInterpolation ( IKeyControl * keyInterface, int keyIndex ) 2113 { 2114 KeyType key; 2115 keyInterface->GetKey ( keyIndex, &key ); 2116 InterpolationType interpolationOutType = getInterpolationOutType ( key.flags ); 2117 if ( interpolationOutType == STEP ) 2118 { 2119 // step always wins 2120 return getNameOfInterpolation( STEP ); 2121 } 2122 int numKeys = keyInterface->GetNumKeys(); 2123 if ( keyIndex + 1 < numKeys ) 2124 { 2125 KeyType nextKey; 2126 keyInterface->GetKey ( keyIndex + 1, &nextKey ); 2127 InterpolationType nextInterpolationInType = getInterpolationInType ( nextKey.flags ); 2128 if ( nextInterpolationInType == STEP ) 2129 { 2130 // step always wins 2131 return getNameOfInterpolation( STEP ); 2132 } 2133 2134 if ( (interpolationOutType == LINEAR) && (nextInterpolationInType == LINEAR) ) 2135 { 2136 // linear only, if both are linear 2137 return getNameOfInterpolation( LINEAR ); 2138 } 2139 else 2140 { 2141 // general case 2142 return getNameOfInterpolation( BEZIER ); 2143 } 2144 } 2145 else 2146 { 2147 return getNameOfInterpolation ( interpolationOutType ); 2148 } 2149 } 2150 2151 2152 //--------------------------------------------------------------- exportSamplingInputSource(const String & baseId,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2153 void AnimationExporter::exportSamplingInputSource ( const String & baseId, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2154 { 2155 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2156 2157 COLLADASW::FloatSource source ( mSW ); 2158 source.setId ( baseId + INPUT_SOURCE_ID_SUFFIX ); 2159 source.setArrayId ( baseId + INPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2160 source.setAccessorStride ( 1 ); 2161 source.getParameterNameList().push_back ( "TIME" ); 2162 source.setAccessorCount ( keyCount ); 2163 source.prepareToAppendValues(); 2164 2165 2166 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2167 { 2168 source.appendValues ( (float)time / (float)TIME_TICKSPERSEC ); 2169 } 2170 2171 source.finish(); 2172 } 2173 2174 2175 2176 //--------------------------------------------------------------- exportSamplingFloatOutputSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2177 void AnimationExporter::exportSamplingFloatOutputSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2178 { 2179 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2180 2181 COLLADASW::FloatSource source ( mSW ); 2182 source.setId ( baseId + OUTPUT_SOURCE_ID_SUFFIX ); 2183 source.setArrayId ( baseId + OUTPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2184 source.setAccessorStride ( 1 ); 2185 2186 if ( animation.getParameter() ) 2187 source.getParameterNameList().push_back ( *(animation.getParameter()) ); 2188 else 2189 source.getParameterNameList().push_back ( EMPTY_STRING ); 2190 2191 source.setAccessorCount ( keyCount ); 2192 source.prepareToAppendValues(); 2193 2194 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 2195 2196 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2197 { 2198 float keyValue; 2199 animation.getController()->GetValue(time, &keyValue, FOREVER, CTRL_ABSOLUTE); 2200 if ( conversionFunctor ) 2201 source.appendValues ( (*conversionFunctor)(keyValue) ); 2202 else 2203 source.appendValues ( keyValue ); 2204 } 2205 2206 source.finish(); 2207 } 2208 2209 2210 //--------------------------------------------------------------- exportSamplingPoint3OutputSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2211 void AnimationExporter::exportSamplingPoint3OutputSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2212 { 2213 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2214 int keyLength = animation.getDimension(); 2215 2216 COLLADASW::FloatSource source ( mSW ); 2217 source.setId ( baseId + OUTPUT_SOURCE_ID_SUFFIX ); 2218 source.setArrayId ( baseId + OUTPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2219 source.setAccessorStride ( keyLength ); 2220 2221 for ( int i = 0; i < keyLength; ++i ) 2222 { 2223 if ( animation.getParameter() ) 2224 source.getParameterNameList().push_back ( * ( animation.getParameter() + i) ); 2225 else 2226 source.getParameterNameList().push_back ( EMPTY_STRING ); 2227 } 2228 2229 source.setAccessorCount ( keyCount ); 2230 source.prepareToAppendValues(); 2231 2232 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 2233 2234 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2235 { 2236 2237 Point3 keyValue; 2238 animation.getController()->GetValue(time, &keyValue, FOREVER, CTRL_ABSOLUTE); 2239 2240 if ( keyLength == 1) 2241 { 2242 if ( conversionFunctor ) 2243 source.appendValues ( (*conversionFunctor) ( keyValue[ animation.getType() - Animation::POSITION_X ] ) ); 2244 else 2245 source.appendValues ( keyValue[ animation.getType() - Animation::POSITION_X ] ); 2246 } 2247 else 2248 { 2249 assert( (keyLength == 3) || (keyLength == 4)); 2250 2251 for ( int j = 0; j < 3; ++j ) 2252 { 2253 if ( conversionFunctor ) 2254 source.appendValues ( (*conversionFunctor) ( keyValue[ j ] ) ); 2255 else 2256 source.appendValues ( keyValue[ j ] ); 2257 } 2258 2259 // If the point3 controller has dimension 4, it is a rgba controller. In this case alpha is one. 2260 if ( keyLength == 4 ) 2261 { 2262 source.appendValues ( 1 ); 2263 } 2264 } 2265 } 2266 source.finish(); 2267 } 2268 2269 2270 //--------------------------------------------------------------- exportSamplingRotationOutputSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2271 void AnimationExporter::exportSamplingRotationOutputSource ( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2272 { 2273 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2274 int keyLength = animation.getDimension(); 2275 2276 COLLADASW::FloatSource source ( mSW ); 2277 source.setId ( baseId + OUTPUT_SOURCE_ID_SUFFIX ); 2278 source.setArrayId ( baseId + OUTPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2279 source.setAccessorStride ( keyLength ); 2280 2281 for ( int i = 0; i < keyLength; ++i ) 2282 { 2283 if ( animation.getParameter() ) 2284 source.getParameterNameList().push_back ( * ( animation.getParameter() + i) ); 2285 else 2286 source.getParameterNameList().push_back ( EMPTY_STRING ); 2287 } 2288 2289 source.setAccessorCount ( keyCount ); 2290 source.prepareToAppendValues(); 2291 2292 ConversionFunctorType conversionFunctor = animation.getConversionFunctor(); 2293 2294 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2295 { 2296 2297 float eulerAngles[ 3 ]; 2298 2299 if ( keyLength == 1 ) 2300 { 2301 Quat quaternion; 2302 animation.getController()->GetValue(time, &quaternion, FOREVER, CTRL_ABSOLUTE); 2303 QuatToEuler(quaternion, eulerAngles, EULERTYPE_XYZ); 2304 } 2305 else 2306 { 2307 AngAxis angleAxis; 2308 animation.getController()->GetValue(time, &angleAxis, FOREVER, CTRL_ABSOLUTE); 2309 Quat quaternion(angleAxis); 2310 quaternion.GetEuler ( &eulerAngles[ 0 ], &eulerAngles[ 1 ], &eulerAngles[ 2 ] ); 2311 } 2312 2313 if ( time > startTime) 2314 patchEuler(mPreviousEulerAngles, eulerAngles); 2315 2316 mPreviousEulerAngles[0] = eulerAngles[0]; 2317 mPreviousEulerAngles[1] = eulerAngles[1]; 2318 mPreviousEulerAngles[2] = eulerAngles[2]; 2319 2320 if ( keyLength == 1) 2321 { 2322 if ( conversionFunctor ) 2323 source.appendValues( (*conversionFunctor)(eulerAngles[ animation.getType() - Animation::ROTATION_X ]) ); 2324 else 2325 source.appendValues( eulerAngles[ animation.getType() - Animation::ROTATION_X ] ); 2326 } 2327 else 2328 { 2329 if ( conversionFunctor ) 2330 { 2331 eulerAngles[0] = (*conversionFunctor)( eulerAngles[0] ); 2332 eulerAngles[1] = (*conversionFunctor)( eulerAngles[1] ); 2333 eulerAngles[2] = (*conversionFunctor)( eulerAngles[2] ); 2334 } 2335 source.appendValues( eulerAngles[0], eulerAngles[1], eulerAngles[2] ); 2336 } 2337 2338 2339 } 2340 source.finish(); 2341 } 2342 2343 exportSamplingTransformationOutputSource(const Animation & animation,const String & baseId,IKeyControl * keyInterface,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2344 void AnimationExporter::exportSamplingTransformationOutputSource( const Animation & animation, const String & baseId, IKeyControl* keyInterface, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2345 { 2346 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2347 int keyLength = animation.getDimension(); 2348 2349 COLLADASW::Float4x4SourceF source ( mSW ); 2350 source.setId ( baseId + OUTPUT_SOURCE_ID_SUFFIX ); 2351 source.setArrayId ( baseId + OUTPUT_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2352 source.setAccessorStride ( keyLength ); 2353 2354 if ( animation.getParameter() ) 2355 source.getParameterNameList().push_back ( * ( animation.getParameter()) ); 2356 else 2357 source.getParameterNameList().push_back ( EMPTY_STRING ); 2358 2359 source.setAccessorCount ( keyCount ); 2360 source.prepareToAppendValues(); 2361 2362 INode * iNode = animation.getNode(); 2363 2364 Matrix3 transformationMatrix, parentTransformationMatrix; 2365 INode* parentINode = iNode->GetParentNode(); 2366 2367 if (parentINode && parentINode->IsRootNode()) 2368 parentINode = 0; 2369 2370 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2371 { 2372 // Export the base NODE TM 2373 transformationMatrix = iNode->GetNodeTM(time); 2374 2375 if (parentINode) 2376 { 2377 // export a relative TM 2378 // We have to use whatever value we exported for this parent 2379 // in order to remain consistent in collada 2380 parentTransformationMatrix = parentINode->GetNodeTM(time); 2381 parentTransformationMatrix.Invert(); 2382 transformationMatrix = transformationMatrix * parentTransformationMatrix; 2383 } 2384 2385 const Matrix3& constTransformationMatrix = transformationMatrix; 2386 for ( int row = 0; row < 3; ++row) 2387 source.appendValues(constTransformationMatrix[0][row], constTransformationMatrix[1][row], constTransformationMatrix[2][row], constTransformationMatrix[3][row]); 2388 source.appendValues(0, 0, 0, 1); 2389 2390 } 2391 2392 source.finish(); 2393 } 2394 2395 2396 //--------------------------------------------------------------- exportSamplingInterpolationSource(const String & baseId,TimeValue startTime,TimeValue endTime,int ticksPerFrame)2397 void AnimationExporter::exportSamplingInterpolationSource ( const String & baseId, TimeValue startTime, TimeValue endTime, int ticksPerFrame ) 2398 { 2399 int keyCount = (endTime - startTime) / ticksPerFrame + 1; 2400 2401 COLLADASW::NameSource source ( mSW ); 2402 source.setId ( baseId + INTERPOLATION_SOURCE_ID_SUFFIX ); 2403 source.setArrayId ( baseId + INTERPOLATION_SOURCE_ID_SUFFIX + ARRAY_ID_SUFFIX ); 2404 source.setAccessorStride ( 1 ); 2405 source.getParameterNameList().push_back ( "INTERPOLATION" ); 2406 source.setAccessorCount ( keyCount ); 2407 source.prepareToAppendValues(); 2408 2409 for (TimeValue time = startTime; time < endTime; time += ticksPerFrame) 2410 source.appendValues ( LINEAR_NAME ); 2411 2412 source.finish(); 2413 } 2414 2415 2416 //--------------------------------------------------------------- exportSampler(const Animation & animation)2417 void AnimationExporter::exportSampler ( const Animation & animation ) 2418 { 2419 2420 if ( animation.hasAnyInputFlagsSet() ) 2421 { 2422 String baseId = getBaseId ( animation ); 2423 2424 LibraryAnimations::Sampler sampler(mSW, baseId + SAMPLER_ID_SUFFIX ); 2425 2426 if ( animation.inputFlagSet(Animation::INPUT) ) 2427 sampler.addInput ( COLLADASW::InputSemantic::INPUT, "#" + baseId + INPUT_SOURCE_ID_SUFFIX ); 2428 2429 if ( animation.inputFlagSet(Animation::OUTPUT) ) 2430 sampler.addInput ( COLLADASW::InputSemantic::OUTPUT, "#" + baseId + OUTPUT_SOURCE_ID_SUFFIX ); 2431 2432 if ( animation.inputFlagSet(Animation::IN_TANGENT) ) 2433 sampler.addInput ( COLLADASW::InputSemantic::IN_TANGENT, "#" + baseId + INTANGENT_SOURCE_ID_SUFFIX ); 2434 2435 if ( animation.inputFlagSet(Animation::OUT_TANGENT) ) 2436 sampler.addInput ( COLLADASW::InputSemantic::OUT_TANGENT, "#" + baseId + OUTTANGENT_SOURCE_ID_SUFFIX ); 2437 2438 if ( animation.inputFlagSet(Animation::INTERPOLATION) ) 2439 sampler.addInput ( COLLADASW::InputSemantic::INTERPOLATION, "#" + baseId + INTERPOLATION_SOURCE_ID_SUFFIX ); 2440 2441 addSampler ( sampler ); 2442 } 2443 } 2444 2445 //--------------------------------------------------------------- exportChannel(const Animation & animation)2446 void AnimationExporter::exportChannel ( const Animation & animation ) 2447 { 2448 if ( animation.hasAnyInputFlagsSet() ) 2449 { 2450 addChannel ( "#" + getBaseId ( animation ) + SAMPLER_ID_SUFFIX, getTarget ( animation ) ); 2451 } 2452 } 2453 2454 2455 2456 //--------------------------------------------------------------- angleApproach(float pval,float & val)2457 void AnimationExporter::angleApproach(float pval, float& val) 2458 { 2459 while (val - pval > MathUtils::PI_f) 2460 val -= MathUtils::PI_f * 2.0f; 2461 while (val - pval < -MathUtils::PI_f) 2462 val += MathUtils::PI_f * 2.0f; 2463 } 2464 2465 2466 //--------------------------------------------------------------- patchEuler(float * pval,float * val)2467 void AnimationExporter::patchEuler(float* pval, float* val) 2468 { 2469 // Approach these Eulers to the previous value. 2470 for (int i = 0; i < 3; ++i) 2471 angleApproach(pval[i], val[i]); 2472 2473 float distanceSq = 0.0f; 2474 for (int i = 0; i < 3; ++i) 2475 distanceSq += (val[i] - pval[i]) * (val[i] - pval[i]); 2476 2477 // All quaternions can be expressed two ways. Check if the second way is better. 2478 float alternative[3] = { val[0] + MathUtils::PI_f, MathUtils::PI_f - val[1], val[2] + MathUtils::PI_f }; 2479 for (int i = 0; i < 3; ++i) 2480 angleApproach(pval[i], alternative[i]); 2481 2482 float alternateDistanceSq = 0.0f; for (int i = 0; i < 3; ++i) alternateDistanceSq += (alternative[i] - pval[i]) * (alternative[i] - pval[i]); 2483 2484 if (alternateDistanceSq < distanceSq) 2485 { 2486 // Pick the alternative 2487 for (int i = 0; i < 3; ++i) 2488 val[i] = alternative[i]; 2489 } 2490 } 2491 2492 } 2493