1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 #include "OgreAnimationTrack.h" 30 #include "OgreAnimation.h" 31 #include "OgreKeyFrame.h" 32 #include "OgreNode.h" 33 #include "OgreLogManager.h" 34 #include "OgreHardwareBufferManager.h" 35 #include "OgreMesh.h" 36 #include "OgreException.h" 37 38 namespace Ogre { 39 40 namespace { 41 // Locally key frame search helper 42 struct KeyFrameTimeLess 43 { operator ()Ogre::__anon4e8e4fcd0111::KeyFrameTimeLess44 bool operator() (const KeyFrame* kf, const KeyFrame* kf2) const 45 { 46 return kf->getTime() < kf2->getTime(); 47 } 48 }; 49 } 50 //--------------------------------------------------------------------- 51 //--------------------------------------------------------------------- AnimationTrack(Animation * parent,unsigned short handle)52 AnimationTrack::AnimationTrack(Animation* parent, unsigned short handle) : 53 mParent(parent), mHandle(handle), mListener(0) 54 { 55 } 56 //--------------------------------------------------------------------- ~AnimationTrack()57 AnimationTrack::~AnimationTrack() 58 { 59 removeAllKeyFrames(); 60 } 61 //--------------------------------------------------------------------- getNumKeyFrames(void) const62 unsigned short AnimationTrack::getNumKeyFrames(void) const 63 { 64 return (unsigned short)mKeyFrames.size(); 65 } 66 //--------------------------------------------------------------------- getKeyFrame(unsigned short index) const67 KeyFrame* AnimationTrack::getKeyFrame(unsigned short index) const 68 { 69 // If you hit this assert, then the keyframe index is out of bounds 70 assert( index < (ushort)mKeyFrames.size() ); 71 72 return mKeyFrames[index]; 73 } 74 //--------------------------------------------------------------------- getKeyFramesAtTime(const TimeIndex & timeIndex,KeyFrame ** keyFrame1,KeyFrame ** keyFrame2,unsigned short * firstKeyIndex) const75 Real AnimationTrack::getKeyFramesAtTime(const TimeIndex& timeIndex, KeyFrame** keyFrame1, KeyFrame** keyFrame2, 76 unsigned short* firstKeyIndex) const 77 { 78 // Parametric time 79 // t1 = time of previous keyframe 80 // t2 = time of next keyframe 81 Real t1, t2; 82 83 Real timePos = timeIndex.getTimePos(); 84 85 // Find first keyframe after or on current time 86 KeyFrameList::const_iterator i; 87 if (timeIndex.hasKeyIndex()) 88 { 89 // Global keyframe index available, map to local keyframe index directly. 90 assert(timeIndex.getKeyIndex() < mKeyFrameIndexMap.size()); 91 i = mKeyFrames.begin() + mKeyFrameIndexMap[timeIndex.getKeyIndex()]; 92 #if OGRE_DEBUG_MODE 93 KeyFrame timeKey(0, timePos); 94 if (i != std::lower_bound(mKeyFrames.begin(), mKeyFrames.end(), &timeKey, KeyFrameTimeLess())) 95 { 96 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 97 "Optimised key frame search failed", 98 "AnimationTrack::getKeyFramesAtTime"); 99 } 100 #endif 101 } 102 else 103 { 104 // Wrap time 105 Real totalAnimationLength = mParent->getLength(); 106 assert(totalAnimationLength > 0.0f && "Invalid animation length!"); 107 108 if( timePos > totalAnimationLength && totalAnimationLength > 0.0f ) 109 timePos = fmod( timePos, totalAnimationLength ); 110 111 // No global keyframe index, need to search with local keyframes. 112 KeyFrame timeKey(0, timePos); 113 i = std::lower_bound(mKeyFrames.begin(), mKeyFrames.end(), &timeKey, KeyFrameTimeLess()); 114 } 115 116 if (i == mKeyFrames.end()) 117 { 118 // There is no keyframe after this time, wrap back to first 119 *keyFrame2 = mKeyFrames.front(); 120 t2 = mParent->getLength() + (*keyFrame2)->getTime(); 121 122 // Use last keyframe as previous keyframe 123 --i; 124 } 125 else 126 { 127 *keyFrame2 = *i; 128 t2 = (*keyFrame2)->getTime(); 129 130 // Find last keyframe before or on current time 131 if (i != mKeyFrames.begin() && timePos < (*i)->getTime()) 132 { 133 --i; 134 } 135 } 136 137 // Fill index of the first key 138 if (firstKeyIndex) 139 { 140 *firstKeyIndex = static_cast<unsigned short>(std::distance(mKeyFrames.begin(), i)); 141 } 142 143 *keyFrame1 = *i; 144 145 t1 = (*keyFrame1)->getTime(); 146 147 if (t1 == t2) 148 { 149 // Same KeyFrame (only one) 150 return 0.0; 151 } 152 else 153 { 154 return (timePos - t1) / (t2 - t1); 155 } 156 } 157 //--------------------------------------------------------------------- createKeyFrame(Real timePos)158 KeyFrame* AnimationTrack::createKeyFrame(Real timePos) 159 { 160 KeyFrame* kf = createKeyFrameImpl(timePos); 161 162 // Insert just before upper bound 163 KeyFrameList::iterator i = 164 std::upper_bound(mKeyFrames.begin(), mKeyFrames.end(), kf, KeyFrameTimeLess()); 165 mKeyFrames.insert(i, kf); 166 167 _keyFrameDataChanged(); 168 mParent->_keyFrameListChanged(); 169 170 return kf; 171 172 } 173 //--------------------------------------------------------------------- removeKeyFrame(unsigned short index)174 void AnimationTrack::removeKeyFrame(unsigned short index) 175 { 176 // If you hit this assert, then the keyframe index is out of bounds 177 assert( index < (ushort)mKeyFrames.size() ); 178 179 KeyFrameList::iterator i = mKeyFrames.begin(); 180 181 i += index; 182 183 OGRE_DELETE *i; 184 185 mKeyFrames.erase(i); 186 187 _keyFrameDataChanged(); 188 mParent->_keyFrameListChanged(); 189 190 191 } 192 //--------------------------------------------------------------------- removeAllKeyFrames(void)193 void AnimationTrack::removeAllKeyFrames(void) 194 { 195 KeyFrameList::iterator i = mKeyFrames.begin(); 196 197 for (; i != mKeyFrames.end(); ++i) 198 { 199 OGRE_DELETE *i; 200 } 201 202 _keyFrameDataChanged(); 203 mParent->_keyFrameListChanged(); 204 205 mKeyFrames.clear(); 206 207 } 208 //--------------------------------------------------------------------- _collectKeyFrameTimes(vector<Real>::type & keyFrameTimes)209 void AnimationTrack::_collectKeyFrameTimes(vector<Real>::type& keyFrameTimes) 210 { 211 for (KeyFrameList::const_iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i) 212 { 213 Real timePos = (*i)->getTime(); 214 215 vector<Real>::type::iterator it = 216 std::lower_bound(keyFrameTimes.begin(), keyFrameTimes.end(), timePos); 217 if (it == keyFrameTimes.end() || *it != timePos) 218 { 219 keyFrameTimes.insert(it, timePos); 220 } 221 } 222 } 223 //--------------------------------------------------------------------- _buildKeyFrameIndexMap(const vector<Real>::type & keyFrameTimes)224 void AnimationTrack::_buildKeyFrameIndexMap(const vector<Real>::type& keyFrameTimes) 225 { 226 // Pre-allocate memory 227 mKeyFrameIndexMap.resize(keyFrameTimes.size() + 1); 228 229 size_t i = 0, j = 0; 230 while (j <= keyFrameTimes.size()) 231 { 232 mKeyFrameIndexMap[j] = static_cast<ushort>(i); 233 while (i < mKeyFrames.size() && mKeyFrames[i]->getTime() <= keyFrameTimes[j]) 234 ++i; 235 ++j; 236 } 237 } 238 //--------------------------------------------------------------------- populateClone(AnimationTrack * clone) const239 void AnimationTrack::populateClone(AnimationTrack* clone) const 240 { 241 for (KeyFrameList::const_iterator i = mKeyFrames.begin(); 242 i != mKeyFrames.end(); ++i) 243 { 244 KeyFrame* clonekf = (*i)->_clone(clone); 245 clone->mKeyFrames.push_back(clonekf); 246 } 247 } 248 //--------------------------------------------------------------------- 249 //--------------------------------------------------------------------- 250 // Numeric specialisations 251 //--------------------------------------------------------------------- NumericAnimationTrack(Animation * parent,unsigned short handle)252 NumericAnimationTrack::NumericAnimationTrack(Animation* parent, 253 unsigned short handle) 254 : AnimationTrack(parent, handle) 255 { 256 } 257 //--------------------------------------------------------------------- NumericAnimationTrack(Animation * parent,unsigned short handle,AnimableValuePtr & target)258 NumericAnimationTrack::NumericAnimationTrack(Animation* parent, 259 unsigned short handle, AnimableValuePtr& target) 260 :AnimationTrack(parent, handle), mTargetAnim(target) 261 { 262 } 263 //--------------------------------------------------------------------- getAssociatedAnimable(void) const264 const AnimableValuePtr& NumericAnimationTrack::getAssociatedAnimable(void) const 265 { 266 return mTargetAnim; 267 } 268 //--------------------------------------------------------------------- setAssociatedAnimable(const AnimableValuePtr & val)269 void NumericAnimationTrack::setAssociatedAnimable(const AnimableValuePtr& val) 270 { 271 mTargetAnim = val; 272 } 273 //--------------------------------------------------------------------- createKeyFrameImpl(Real time)274 KeyFrame* NumericAnimationTrack::createKeyFrameImpl(Real time) 275 { 276 return OGRE_NEW NumericKeyFrame(this, time); 277 } 278 //--------------------------------------------------------------------- getInterpolatedKeyFrame(const TimeIndex & timeIndex,KeyFrame * kf) const279 void NumericAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, 280 KeyFrame* kf) const 281 { 282 if (mListener) 283 { 284 if (mListener->getInterpolatedKeyFrame(this, timeIndex, kf)) 285 return; 286 } 287 288 NumericKeyFrame* kret = static_cast<NumericKeyFrame*>(kf); 289 290 // Keyframe pointers 291 KeyFrame *kBase1, *kBase2; 292 NumericKeyFrame *k1, *k2; 293 unsigned short firstKeyIndex; 294 295 Real t = this->getKeyFramesAtTime(timeIndex, &kBase1, &kBase2, &firstKeyIndex); 296 k1 = static_cast<NumericKeyFrame*>(kBase1); 297 k2 = static_cast<NumericKeyFrame*>(kBase2); 298 299 if (t == 0.0) 300 { 301 // Just use k1 302 kret->setValue(k1->getValue()); 303 } 304 else 305 { 306 // Interpolate by t 307 AnyNumeric diff = k2->getValue() - k1->getValue(); 308 kret->setValue(k1->getValue() + diff * t); 309 } 310 } 311 //--------------------------------------------------------------------- apply(const TimeIndex & timeIndex,Real weight,Real scale)312 void NumericAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale) 313 { 314 applyToAnimable(mTargetAnim, timeIndex, weight, scale); 315 } 316 //--------------------------------------------------------------------- applyToAnimable(const AnimableValuePtr & anim,const TimeIndex & timeIndex,Real weight,Real scale)317 void NumericAnimationTrack::applyToAnimable(const AnimableValuePtr& anim, const TimeIndex& timeIndex, 318 Real weight, Real scale) 319 { 320 // Nothing to do if no keyframes or zero weight, scale 321 if (mKeyFrames.empty() || !weight || !scale) 322 return; 323 324 NumericKeyFrame kf(0, timeIndex.getTimePos()); 325 getInterpolatedKeyFrame(timeIndex, &kf); 326 // add to existing. Weights are not relative, but treated as 327 // absolute multipliers for the animation 328 AnyNumeric val = kf.getValue() * (weight * scale); 329 330 anim->applyDeltaValue(val); 331 332 } 333 //-------------------------------------------------------------------------- createNumericKeyFrame(Real timePos)334 NumericKeyFrame* NumericAnimationTrack::createNumericKeyFrame(Real timePos) 335 { 336 return static_cast<NumericKeyFrame*>(createKeyFrame(timePos)); 337 } 338 //-------------------------------------------------------------------------- getNumericKeyFrame(unsigned short index) const339 NumericKeyFrame* NumericAnimationTrack::getNumericKeyFrame(unsigned short index) const 340 { 341 return static_cast<NumericKeyFrame*>(getKeyFrame(index)); 342 } 343 //--------------------------------------------------------------------- _clone(Animation * newParent) const344 NumericAnimationTrack* NumericAnimationTrack::_clone(Animation* newParent) const 345 { 346 NumericAnimationTrack* newTrack = 347 newParent->createNumericTrack(mHandle); 348 newTrack->mTargetAnim = mTargetAnim; 349 populateClone(newTrack); 350 return newTrack; 351 } 352 //--------------------------------------------------------------------- 353 //--------------------------------------------------------------------- 354 // Node specialisations 355 //--------------------------------------------------------------------- NodeAnimationTrack(Animation * parent,unsigned short handle)356 NodeAnimationTrack::NodeAnimationTrack(Animation* parent, unsigned short handle) 357 : AnimationTrack(parent, handle), mTargetNode(0) 358 , mSplines(0), mSplineBuildNeeded(false) 359 , mUseShortestRotationPath(true) 360 { 361 } 362 //--------------------------------------------------------------------- NodeAnimationTrack(Animation * parent,unsigned short handle,Node * targetNode)363 NodeAnimationTrack::NodeAnimationTrack(Animation* parent, unsigned short handle, 364 Node* targetNode) 365 : AnimationTrack(parent, handle), mTargetNode(targetNode) 366 , mSplines(0), mSplineBuildNeeded(false) 367 , mUseShortestRotationPath(true) 368 { 369 } 370 //--------------------------------------------------------------------- ~NodeAnimationTrack()371 NodeAnimationTrack::~NodeAnimationTrack() 372 { 373 OGRE_DELETE_T(mSplines, Splines, MEMCATEGORY_ANIMATION); 374 } 375 //--------------------------------------------------------------------- getInterpolatedKeyFrame(const TimeIndex & timeIndex,KeyFrame * kf) const376 void NodeAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const 377 { 378 if (mListener) 379 { 380 if (mListener->getInterpolatedKeyFrame(this, timeIndex, kf)) 381 return; 382 } 383 384 TransformKeyFrame* kret = static_cast<TransformKeyFrame*>(kf); 385 386 // Keyframe pointers 387 KeyFrame *kBase1, *kBase2; 388 TransformKeyFrame *k1, *k2; 389 unsigned short firstKeyIndex; 390 391 Real t = this->getKeyFramesAtTime(timeIndex, &kBase1, &kBase2, &firstKeyIndex); 392 k1 = static_cast<TransformKeyFrame*>(kBase1); 393 k2 = static_cast<TransformKeyFrame*>(kBase2); 394 395 if (t == 0.0) 396 { 397 // Just use k1 398 kret->setRotation(k1->getRotation()); 399 kret->setTranslate(k1->getTranslate()); 400 kret->setScale(k1->getScale()); 401 } 402 else 403 { 404 // Interpolate by t 405 Animation::InterpolationMode im = mParent->getInterpolationMode(); 406 Animation::RotationInterpolationMode rim = 407 mParent->getRotationInterpolationMode(); 408 Vector3 base; 409 switch(im) 410 { 411 case Animation::IM_LINEAR: 412 // Interpolate linearly 413 // Rotation 414 // Interpolate to nearest rotation if mUseShortestRotationPath set 415 if (rim == Animation::RIM_LINEAR) 416 { 417 kret->setRotation( Quaternion::nlerp(t, k1->getRotation(), 418 k2->getRotation(), mUseShortestRotationPath) ); 419 } 420 else //if (rim == Animation::RIM_SPHERICAL) 421 { 422 kret->setRotation( Quaternion::Slerp(t, k1->getRotation(), 423 k2->getRotation(), mUseShortestRotationPath) ); 424 } 425 426 // Translation 427 base = k1->getTranslate(); 428 kret->setTranslate( base + ((k2->getTranslate() - base) * t) ); 429 430 // Scale 431 base = k1->getScale(); 432 kret->setScale( base + ((k2->getScale() - base) * t) ); 433 break; 434 435 case Animation::IM_SPLINE: 436 // Spline interpolation 437 438 // Build splines if required 439 if (mSplineBuildNeeded) 440 { 441 buildInterpolationSplines(); 442 } 443 444 // Rotation, take mUseShortestRotationPath into account 445 kret->setRotation( mSplines->rotationSpline.interpolate(firstKeyIndex, t, 446 mUseShortestRotationPath) ); 447 448 // Translation 449 kret->setTranslate( mSplines->positionSpline.interpolate(firstKeyIndex, t) ); 450 451 // Scale 452 kret->setScale( mSplines->scaleSpline.interpolate(firstKeyIndex, t) ); 453 454 break; 455 } 456 457 } 458 } 459 //--------------------------------------------------------------------- apply(const TimeIndex & timeIndex,Real weight,Real scale)460 void NodeAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale) 461 { 462 applyToNode(mTargetNode, timeIndex, weight, scale); 463 464 } 465 //--------------------------------------------------------------------- getAssociatedNode(void) const466 Node* NodeAnimationTrack::getAssociatedNode(void) const 467 { 468 return mTargetNode; 469 } 470 //--------------------------------------------------------------------- setAssociatedNode(Node * node)471 void NodeAnimationTrack::setAssociatedNode(Node* node) 472 { 473 mTargetNode = node; 474 } 475 //--------------------------------------------------------------------- applyToNode(Node * node,const TimeIndex & timeIndex,Real weight,Real scl)476 void NodeAnimationTrack::applyToNode(Node* node, const TimeIndex& timeIndex, Real weight, 477 Real scl) 478 { 479 // Nothing to do if no keyframes or zero weight or no node 480 if (mKeyFrames.empty() || !weight || !node) 481 return; 482 483 TransformKeyFrame kf(0, timeIndex.getTimePos()); 484 getInterpolatedKeyFrame(timeIndex, &kf); 485 486 // add to existing. Weights are not relative, but treated as absolute multipliers for the animation 487 Vector3 translate = kf.getTranslate() * weight * scl; 488 node->translate(translate); 489 490 // interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full 491 Quaternion rotate; 492 Animation::RotationInterpolationMode rim = 493 mParent->getRotationInterpolationMode(); 494 if (rim == Animation::RIM_LINEAR) 495 { 496 rotate = Quaternion::nlerp(weight, Quaternion::IDENTITY, kf.getRotation(), mUseShortestRotationPath); 497 } 498 else //if (rim == Animation::RIM_SPHERICAL) 499 { 500 rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation(), mUseShortestRotationPath); 501 } 502 node->rotate(rotate); 503 504 Vector3 scale = kf.getScale(); 505 // Not sure how to modify scale for cumulative anims... leave it alone 506 //scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE; 507 if (scale != Vector3::UNIT_SCALE) 508 { 509 if (scl != 1.0f) 510 scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * scl; 511 else if (weight != 1.0f) 512 scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * weight; 513 } 514 node->scale(scale); 515 516 } 517 //--------------------------------------------------------------------- buildInterpolationSplines(void) const518 void NodeAnimationTrack::buildInterpolationSplines(void) const 519 { 520 // Allocate splines if not exists 521 if (!mSplines) 522 { 523 mSplines = OGRE_NEW_T(Splines, MEMCATEGORY_ANIMATION); 524 } 525 526 // Cache to register for optimisation 527 Splines* splines = mSplines; 528 529 // Don't calc automatically, do it on request at the end 530 splines->positionSpline.setAutoCalculate(false); 531 splines->rotationSpline.setAutoCalculate(false); 532 splines->scaleSpline.setAutoCalculate(false); 533 534 splines->positionSpline.clear(); 535 splines->rotationSpline.clear(); 536 splines->scaleSpline.clear(); 537 538 KeyFrameList::const_iterator i, iend; 539 iend = mKeyFrames.end(); // precall to avoid overhead 540 for (i = mKeyFrames.begin(); i != iend; ++i) 541 { 542 TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(*i); 543 splines->positionSpline.addPoint(kf->getTranslate()); 544 splines->rotationSpline.addPoint(kf->getRotation()); 545 splines->scaleSpline.addPoint(kf->getScale()); 546 } 547 548 splines->positionSpline.recalcTangents(); 549 splines->rotationSpline.recalcTangents(); 550 splines->scaleSpline.recalcTangents(); 551 552 553 mSplineBuildNeeded = false; 554 } 555 556 //--------------------------------------------------------------------- setUseShortestRotationPath(bool useShortestPath)557 void NodeAnimationTrack::setUseShortestRotationPath(bool useShortestPath) 558 { 559 mUseShortestRotationPath = useShortestPath ; 560 } 561 562 //--------------------------------------------------------------------- getUseShortestRotationPath() const563 bool NodeAnimationTrack::getUseShortestRotationPath() const 564 { 565 return mUseShortestRotationPath ; 566 } 567 //--------------------------------------------------------------------- _keyFrameDataChanged(void) const568 void NodeAnimationTrack::_keyFrameDataChanged(void) const 569 { 570 mSplineBuildNeeded = true; 571 } 572 //--------------------------------------------------------------------- hasNonZeroKeyFrames(void) const573 bool NodeAnimationTrack::hasNonZeroKeyFrames(void) const 574 { 575 KeyFrameList::const_iterator i = mKeyFrames.begin(); 576 for (; i != mKeyFrames.end(); ++i) 577 { 578 // look for keyframes which have any component which is non-zero 579 // Since exporters can be a little inaccurate sometimes we use a 580 // tolerance value rather than looking for nothing 581 TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(*i); 582 Vector3 trans = kf->getTranslate(); 583 Vector3 scale = kf->getScale(); 584 Vector3 axis; 585 Radian angle; 586 kf->getRotation().ToAngleAxis(angle, axis); 587 Real tolerance = 1e-3f; 588 if (!trans.positionEquals(Vector3::ZERO, tolerance) || 589 !scale.positionEquals(Vector3::UNIT_SCALE, tolerance) || 590 !Math::RealEqual(angle.valueRadians(), 0.0f, tolerance)) 591 { 592 return true; 593 } 594 595 } 596 597 return false; 598 } 599 //--------------------------------------------------------------------- optimise(void)600 void NodeAnimationTrack::optimise(void) 601 { 602 // Eliminate duplicate keyframes from 2nd to penultimate keyframe 603 // NB only eliminate middle keys from sequences of 5+ identical keyframes 604 // since we need to preserve the boundary keys in place, and we need 605 // 2 at each end to preserve tangents for spline interpolation 606 Vector3 lasttrans = Vector3::ZERO; 607 Vector3 lastscale = Vector3::ZERO; 608 Quaternion lastorientation; 609 KeyFrameList::iterator i = mKeyFrames.begin(); 610 Radian quatTolerance(1e-3f); 611 list<unsigned short>::type removeList; 612 unsigned short k = 0; 613 ushort dupKfCount = 0; 614 for (; i != mKeyFrames.end(); ++i, ++k) 615 { 616 TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(*i); 617 Vector3 newtrans = kf->getTranslate(); 618 Vector3 newscale = kf->getScale(); 619 Quaternion neworientation = kf->getRotation(); 620 // Ignore first keyframe; now include the last keyframe as we eliminate 621 // only k-2 in a group of 5 to ensure we only eliminate middle keys 622 if (i != mKeyFrames.begin() && 623 newtrans.positionEquals(lasttrans) && 624 newscale.positionEquals(lastscale) && 625 neworientation.equals(lastorientation, quatTolerance)) 626 { 627 ++dupKfCount; 628 629 // 4 indicates this is the 5th duplicate keyframe 630 if (dupKfCount == 4) 631 { 632 // remove the 'middle' keyframe 633 removeList.push_back(k-2); 634 --dupKfCount; 635 } 636 } 637 else 638 { 639 // reset 640 dupKfCount = 0; 641 lasttrans = newtrans; 642 lastscale = newscale; 643 lastorientation = neworientation; 644 } 645 } 646 647 // Now remove keyframes, in reverse order to avoid index revocation 648 list<unsigned short>::type::reverse_iterator r = removeList.rbegin(); 649 for (; r!= removeList.rend(); ++r) 650 { 651 removeKeyFrame(*r); 652 } 653 654 655 } 656 //-------------------------------------------------------------------------- createKeyFrameImpl(Real time)657 KeyFrame* NodeAnimationTrack::createKeyFrameImpl(Real time) 658 { 659 return OGRE_NEW TransformKeyFrame(this, time); 660 } 661 //-------------------------------------------------------------------------- createNodeKeyFrame(Real timePos)662 TransformKeyFrame* NodeAnimationTrack::createNodeKeyFrame(Real timePos) 663 { 664 return static_cast<TransformKeyFrame*>(createKeyFrame(timePos)); 665 } 666 //-------------------------------------------------------------------------- getNodeKeyFrame(unsigned short index) const667 TransformKeyFrame* NodeAnimationTrack::getNodeKeyFrame(unsigned short index) const 668 { 669 return static_cast<TransformKeyFrame*>(getKeyFrame(index)); 670 } 671 //--------------------------------------------------------------------- _clone(Animation * newParent) const672 NodeAnimationTrack* NodeAnimationTrack::_clone(Animation* newParent) const 673 { 674 NodeAnimationTrack* newTrack = 675 newParent->createNodeTrack(mHandle, mTargetNode); 676 newTrack->mUseShortestRotationPath = mUseShortestRotationPath; 677 populateClone(newTrack); 678 return newTrack; 679 } 680 //-------------------------------------------------------------------------- _applyBaseKeyFrame(const KeyFrame * b)681 void NodeAnimationTrack::_applyBaseKeyFrame(const KeyFrame* b) 682 { 683 const TransformKeyFrame* base = static_cast<const TransformKeyFrame*>(b); 684 685 for (KeyFrameList::iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i) 686 { 687 TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(*i); 688 kf->setTranslate(kf->getTranslate() - base->getTranslate()); 689 kf->setRotation(base->getRotation().Inverse() * kf->getRotation()); 690 kf->setScale(kf->getScale() * (Vector3::UNIT_SCALE / base->getScale())); 691 } 692 693 } 694 //-------------------------------------------------------------------------- VertexAnimationTrack(Animation * parent,unsigned short handle,VertexAnimationType animType)695 VertexAnimationTrack::VertexAnimationTrack(Animation* parent, 696 unsigned short handle, VertexAnimationType animType) 697 : AnimationTrack(parent, handle) 698 , mAnimationType(animType) 699 { 700 } 701 //-------------------------------------------------------------------------- VertexAnimationTrack(Animation * parent,unsigned short handle,VertexAnimationType animType,VertexData * targetData,TargetMode target)702 VertexAnimationTrack::VertexAnimationTrack(Animation* parent, unsigned short handle, 703 VertexAnimationType animType, VertexData* targetData, TargetMode target) 704 : AnimationTrack(parent, handle) 705 , mAnimationType(animType) 706 , mTargetVertexData(targetData) 707 , mTargetMode(target) 708 { 709 } 710 //-------------------------------------------------------------------------- createVertexMorphKeyFrame(Real timePos)711 VertexMorphKeyFrame* VertexAnimationTrack::createVertexMorphKeyFrame(Real timePos) 712 { 713 if (mAnimationType != VAT_MORPH) 714 { 715 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 716 "Morph keyframes can only be created on vertex tracks of type morph.", 717 "VertexAnimationTrack::createVertexMorphKeyFrame"); 718 } 719 return static_cast<VertexMorphKeyFrame*>(createKeyFrame(timePos)); 720 } 721 //-------------------------------------------------------------------------- createVertexPoseKeyFrame(Real timePos)722 VertexPoseKeyFrame* VertexAnimationTrack::createVertexPoseKeyFrame(Real timePos) 723 { 724 if (mAnimationType != VAT_POSE) 725 { 726 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 727 "Pose keyframes can only be created on vertex tracks of type pose.", 728 "VertexAnimationTrack::createVertexPoseKeyFrame"); 729 } 730 return static_cast<VertexPoseKeyFrame*>(createKeyFrame(timePos)); 731 } 732 //-------------------------------------------------------------------------- getInterpolatedKeyFrame(const TimeIndex & timeIndex,KeyFrame * kf) const733 void VertexAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const 734 { 735 // Only relevant for pose animation 736 if (mAnimationType == VAT_POSE) 737 { 738 // Get keyframes 739 KeyFrame *kf1, *kf2; 740 Real t = getKeyFramesAtTime(timeIndex, &kf1, &kf2); 741 742 VertexPoseKeyFrame* vkfOut = static_cast<VertexPoseKeyFrame*>(kf); 743 VertexPoseKeyFrame* vkf1 = static_cast<VertexPoseKeyFrame*>(kf1); 744 VertexPoseKeyFrame* vkf2 = static_cast<VertexPoseKeyFrame*>(kf2); 745 746 // For each pose reference in key 1, we need to locate the entry in 747 // key 2 and interpolate the influence 748 const VertexPoseKeyFrame::PoseRefList& poseList1 = vkf1->getPoseReferences(); 749 const VertexPoseKeyFrame::PoseRefList& poseList2 = vkf2->getPoseReferences(); 750 for (VertexPoseKeyFrame::PoseRefList::const_iterator p1 = poseList1.begin(); 751 p1 != poseList1.end(); ++p1) 752 { 753 Real startInfluence = p1->influence; 754 Real endInfluence = 0; 755 // Search for entry in keyframe 2 list (if not there, will be 0) 756 for (VertexPoseKeyFrame::PoseRefList::const_iterator p2 = poseList2.begin(); 757 p2 != poseList2.end(); ++p2) 758 { 759 if (p1->poseIndex == p2->poseIndex) 760 { 761 endInfluence = p2->influence; 762 break; 763 } 764 } 765 // Interpolate influence 766 Real influence = startInfluence + t*(endInfluence - startInfluence); 767 768 vkfOut->addPoseReference(p1->poseIndex, influence); 769 770 771 } 772 // Now deal with any poses in key 2 which are not in key 1 773 for (VertexPoseKeyFrame::PoseRefList::const_iterator p2 = poseList2.begin(); 774 p2 != poseList2.end(); ++p2) 775 { 776 bool found = false; 777 for (VertexPoseKeyFrame::PoseRefList::const_iterator p1 = poseList1.begin(); 778 p1 != poseList1.end(); ++p1) 779 { 780 if (p1->poseIndex == p2->poseIndex) 781 { 782 found = true; 783 break; 784 } 785 } 786 if (!found) 787 { 788 // Need to apply this pose too, scaled from 0 start 789 Real influence = t * p2->influence; 790 791 vkfOut->addPoseReference(p2->poseIndex, influence); 792 793 } 794 } // key 2 iteration 795 796 } 797 798 799 } 800 //-------------------------------------------------------------------------- getVertexAnimationIncludesNormals() const801 bool VertexAnimationTrack::getVertexAnimationIncludesNormals() const 802 { 803 if (mAnimationType == VAT_NONE) 804 return false; 805 806 if (mAnimationType == VAT_MORPH) 807 { 808 bool normals = false; 809 for (KeyFrameList::const_iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i) 810 { 811 VertexMorphKeyFrame* kf = static_cast<VertexMorphKeyFrame*>(*i); 812 bool thisnorm = kf->getVertexBuffer()->getVertexSize() > 12; 813 if (i == mKeyFrames.begin()) 814 normals = thisnorm; 815 else 816 // Only support normals if ALL keyframes include them 817 normals = normals && thisnorm; 818 819 } 820 return normals; 821 } 822 else 823 { 824 // needs to derive from Mesh::PoseList, can't tell here 825 return false; 826 } 827 828 829 } 830 //-------------------------------------------------------------------------- apply(const TimeIndex & timeIndex,Real weight,Real scale)831 void VertexAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale) 832 { 833 applyToVertexData(mTargetVertexData, timeIndex, weight); 834 } 835 //-------------------------------------------------------------------------- applyToVertexData(VertexData * data,const TimeIndex & timeIndex,Real weight,const PoseList * poseList)836 void VertexAnimationTrack::applyToVertexData(VertexData* data, 837 const TimeIndex& timeIndex, Real weight, const PoseList* poseList) 838 { 839 // Nothing to do if no keyframes or no vertex data 840 if (mKeyFrames.empty() || !data) 841 return; 842 843 // Get keyframes 844 KeyFrame *kf1, *kf2; 845 Real t = getKeyFramesAtTime(timeIndex, &kf1, &kf2); 846 847 if (mAnimationType == VAT_MORPH) 848 { 849 VertexMorphKeyFrame* vkf1 = static_cast<VertexMorphKeyFrame*>(kf1); 850 VertexMorphKeyFrame* vkf2 = static_cast<VertexMorphKeyFrame*>(kf2); 851 852 if (mTargetMode == TM_HARDWARE) 853 { 854 // If target mode is hardware, need to bind our 2 keyframe buffers, 855 // one to main pos, one to morph target texcoord 856 assert(!data->hwAnimationDataList.empty() && 857 "Haven't set up hardware vertex animation elements!"); 858 859 // no use for TempBlendedBufferInfo here btw 860 // NB we assume that position buffer is unshared, except for normals 861 // VertexDeclaration::getAutoOrganisedDeclaration should see to that 862 const VertexElement* posElem = 863 data->vertexDeclaration->findElementBySemantic(VES_POSITION); 864 // Set keyframe1 data as original position 865 data->vertexBufferBinding->setBinding( 866 posElem->getSource(), vkf1->getVertexBuffer()); 867 // Set keyframe2 data as derived 868 data->vertexBufferBinding->setBinding( 869 data->hwAnimationDataList[0].targetBufferIndex, 870 vkf2->getVertexBuffer()); 871 // save T for use later 872 data->hwAnimationDataList[0].parametric = t; 873 874 } 875 else 876 { 877 // If target mode is software, need to software interpolate each vertex 878 879 Mesh::softwareVertexMorph( 880 t, vkf1->getVertexBuffer(), vkf2->getVertexBuffer(), data); 881 } 882 } 883 else 884 { 885 // Pose 886 887 VertexPoseKeyFrame* vkf1 = static_cast<VertexPoseKeyFrame*>(kf1); 888 VertexPoseKeyFrame* vkf2 = static_cast<VertexPoseKeyFrame*>(kf2); 889 890 // For each pose reference in key 1, we need to locate the entry in 891 // key 2 and interpolate the influence 892 const VertexPoseKeyFrame::PoseRefList& poseList1 = vkf1->getPoseReferences(); 893 const VertexPoseKeyFrame::PoseRefList& poseList2 = vkf2->getPoseReferences(); 894 for (VertexPoseKeyFrame::PoseRefList::const_iterator p1 = poseList1.begin(); 895 p1 != poseList1.end(); ++p1) 896 { 897 Real startInfluence = p1->influence; 898 Real endInfluence = 0; 899 // Search for entry in keyframe 2 list (if not there, will be 0) 900 for (VertexPoseKeyFrame::PoseRefList::const_iterator p2 = poseList2.begin(); 901 p2 != poseList2.end(); ++p2) 902 { 903 if (p1->poseIndex == p2->poseIndex) 904 { 905 endInfluence = p2->influence; 906 break; 907 } 908 } 909 // Interpolate influence 910 Real influence = startInfluence + t*(endInfluence - startInfluence); 911 // Scale by animation weight 912 influence = weight * influence; 913 // Get pose 914 assert (poseList && p1->poseIndex < poseList->size()); 915 Pose* pose = (*poseList)[p1->poseIndex]; 916 // apply 917 applyPoseToVertexData(pose, data, influence); 918 } 919 // Now deal with any poses in key 2 which are not in key 1 920 for (VertexPoseKeyFrame::PoseRefList::const_iterator p2 = poseList2.begin(); 921 p2 != poseList2.end(); ++p2) 922 { 923 bool found = false; 924 for (VertexPoseKeyFrame::PoseRefList::const_iterator p1 = poseList1.begin(); 925 p1 != poseList1.end(); ++p1) 926 { 927 if (p1->poseIndex == p2->poseIndex) 928 { 929 found = true; 930 break; 931 } 932 } 933 if (!found) 934 { 935 // Need to apply this pose too, scaled from 0 start 936 Real influence = t * p2->influence; 937 // Scale by animation weight 938 influence = weight * influence; 939 // Get pose 940 assert (poseList && p2->poseIndex <= poseList->size()); 941 const Pose* pose = (*poseList)[p2->poseIndex]; 942 // apply 943 applyPoseToVertexData(pose, data, influence); 944 } 945 } // key 2 iteration 946 } // morph or pose animation 947 } 948 //----------------------------------------------------------------------------- applyPoseToVertexData(const Pose * pose,VertexData * data,Real influence)949 void VertexAnimationTrack::applyPoseToVertexData(const Pose* pose, 950 VertexData* data, Real influence) 951 { 952 if (mTargetMode == TM_HARDWARE) 953 { 954 // Hardware 955 // If target mode is hardware, need to bind our pose buffer 956 // to a target texcoord 957 assert(!data->hwAnimationDataList.empty() && 958 "Haven't set up hardware vertex animation elements!"); 959 // no use for TempBlendedBufferInfo here btw 960 // Set pose target as required 961 size_t hwIndex = data->hwAnimDataItemsUsed++; 962 // If we try to use too many poses, ignore extras 963 if (hwIndex < data->hwAnimationDataList.size()) 964 { 965 VertexData::HardwareAnimationData& animData = data->hwAnimationDataList[hwIndex]; 966 data->vertexBufferBinding->setBinding( 967 animData.targetBufferIndex, 968 pose->_getHardwareVertexBuffer(data)); 969 // save final influence in parametric 970 animData.parametric = influence; 971 972 } 973 974 } 975 else 976 { 977 // Software 978 Mesh::softwareVertexPoseBlend(influence, pose->getVertexOffsets(), pose->getNormals(), data); 979 } 980 981 } 982 //-------------------------------------------------------------------------- getVertexMorphKeyFrame(unsigned short index) const983 VertexMorphKeyFrame* VertexAnimationTrack::getVertexMorphKeyFrame(unsigned short index) const 984 { 985 if (mAnimationType != VAT_MORPH) 986 { 987 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 988 "Morph keyframes can only be created on vertex tracks of type morph.", 989 "VertexAnimationTrack::getVertexMorphKeyFrame"); 990 } 991 992 return static_cast<VertexMorphKeyFrame*>(getKeyFrame(index)); 993 } 994 //-------------------------------------------------------------------------- getVertexPoseKeyFrame(unsigned short index) const995 VertexPoseKeyFrame* VertexAnimationTrack::getVertexPoseKeyFrame(unsigned short index) const 996 { 997 if (mAnimationType != VAT_POSE) 998 { 999 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1000 "Pose keyframes can only be created on vertex tracks of type pose.", 1001 "VertexAnimationTrack::getVertexPoseKeyFrame"); 1002 } 1003 1004 return static_cast<VertexPoseKeyFrame*>(getKeyFrame(index)); 1005 } 1006 //-------------------------------------------------------------------------- createKeyFrameImpl(Real time)1007 KeyFrame* VertexAnimationTrack::createKeyFrameImpl(Real time) 1008 { 1009 switch(mAnimationType) 1010 { 1011 default: 1012 case VAT_MORPH: 1013 return OGRE_NEW VertexMorphKeyFrame(this, time); 1014 case VAT_POSE: 1015 return OGRE_NEW VertexPoseKeyFrame(this, time); 1016 }; 1017 1018 } 1019 //--------------------------------------------------------------------- hasNonZeroKeyFrames(void) const1020 bool VertexAnimationTrack::hasNonZeroKeyFrames(void) const 1021 { 1022 if (mAnimationType == VAT_MORPH) 1023 { 1024 return !mKeyFrames.empty(); 1025 } 1026 else 1027 { 1028 1029 KeyFrameList::const_iterator i = mKeyFrames.begin(); 1030 for (; i != mKeyFrames.end(); ++i) 1031 { 1032 // look for keyframes which have a pose influence which is non-zero 1033 const VertexPoseKeyFrame* kf = static_cast<const VertexPoseKeyFrame*>(*i); 1034 VertexPoseKeyFrame::ConstPoseRefIterator poseIt 1035 = kf->getPoseReferenceIterator(); 1036 while (poseIt.hasMoreElements()) 1037 { 1038 const VertexPoseKeyFrame::PoseRef& poseRef = poseIt.getNext(); 1039 if (poseRef.influence > 0.0f) 1040 return true; 1041 } 1042 1043 } 1044 1045 return false; 1046 } 1047 } 1048 //--------------------------------------------------------------------- optimise(void)1049 void VertexAnimationTrack::optimise(void) 1050 { 1051 // TODO - remove sequences of duplicate pose references? 1052 1053 1054 } 1055 //--------------------------------------------------------------------- _clone(Animation * newParent) const1056 VertexAnimationTrack* VertexAnimationTrack::_clone(Animation* newParent) const 1057 { 1058 VertexAnimationTrack* newTrack = 1059 newParent->createVertexTrack(mHandle, mAnimationType); 1060 newTrack->mTargetMode = mTargetMode; 1061 populateClone(newTrack); 1062 return newTrack; 1063 } 1064 //-------------------------------------------------------------------------- _applyBaseKeyFrame(const KeyFrame * b)1065 void VertexAnimationTrack::_applyBaseKeyFrame(const KeyFrame* b) 1066 { 1067 const VertexPoseKeyFrame* base = static_cast<const VertexPoseKeyFrame*>(b); 1068 1069 for (KeyFrameList::iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i) 1070 { 1071 VertexPoseKeyFrame* kf = static_cast<VertexPoseKeyFrame*>(*i); 1072 1073 kf->_applyBaseKeyFrame(base); 1074 } 1075 1076 } 1077 1078 1079 } 1080 1081