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