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-2014 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 "OgreAnimation.h"
30 #include "OgreKeyFrame.h"
31 #include "OgreEntity.h"
32 #include "OgreSubEntity.h"
33 
34 namespace Ogre {
35 
36     Animation::InterpolationMode Animation::msDefaultInterpolationMode = Animation::IM_LINEAR;
37     Animation::RotationInterpolationMode
38         Animation::msDefaultRotationInterpolationMode = Animation::RIM_LINEAR;
39     //---------------------------------------------------------------------
Animation(const String & name,Real length)40     Animation::Animation(const String& name, Real length)
41         : mName(name)
42         , mLength(length)
43         , mInterpolationMode(msDefaultInterpolationMode)
44         , mRotationInterpolationMode(msDefaultRotationInterpolationMode)
45         , mKeyFrameTimesDirty(false)
46         , mUseBaseKeyFrame(false)
47         , mBaseKeyFrameTime(0.0f)
48         , mBaseKeyFrameAnimationName(BLANKSTRING)
49         , mContainer(0)
50     {
51     }
52     //---------------------------------------------------------------------
~Animation()53     Animation::~Animation()
54     {
55         destroyAllTracks();
56     }
57     //---------------------------------------------------------------------
getLength(void) const58     Real Animation::getLength(void) const
59     {
60         return mLength;
61     }
62     //---------------------------------------------------------------------
setLength(Real len)63     void Animation::setLength(Real len)
64     {
65         mLength = len;
66     }
67     //---------------------------------------------------------------------
createNodeTrack(unsigned short handle)68     NodeAnimationTrack* Animation::createNodeTrack(unsigned short handle)
69     {
70         if (hasNodeTrack(handle))
71         {
72             OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
73                 "Node track with the specified handle " +
74                 StringConverter::toString(handle) + " already exists",
75                 "Animation::createNodeTrack");
76         }
77 
78         NodeAnimationTrack* ret = OGRE_NEW NodeAnimationTrack(this, handle);
79 
80         mNodeTrackList[handle] = ret;
81         return ret;
82     }
83     //---------------------------------------------------------------------
createNodeTrack(unsigned short handle,Node * node)84     NodeAnimationTrack* Animation::createNodeTrack(unsigned short handle, Node* node)
85     {
86         NodeAnimationTrack* ret = createNodeTrack(handle);
87 
88         ret->setAssociatedNode(node);
89 
90         return ret;
91     }
92     //---------------------------------------------------------------------
getNumNodeTracks(void) const93     unsigned short Animation::getNumNodeTracks(void) const
94     {
95         return (unsigned short)mNodeTrackList.size();
96     }
97     //---------------------------------------------------------------------
hasNodeTrack(unsigned short handle) const98     bool Animation::hasNodeTrack(unsigned short handle) const
99     {
100         return (mNodeTrackList.find(handle) != mNodeTrackList.end());
101     }
102     //---------------------------------------------------------------------
getNodeTrack(unsigned short handle) const103     NodeAnimationTrack* Animation::getNodeTrack(unsigned short handle) const
104     {
105         NodeTrackList::const_iterator i = mNodeTrackList.find(handle);
106 
107         if (i == mNodeTrackList.end())
108         {
109             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
110                 "Cannot find node track with the specified handle " +
111                 StringConverter::toString(handle),
112                 "Animation::getNodeTrack");
113         }
114 
115         return i->second;
116 
117     }
118     //---------------------------------------------------------------------
destroyNodeTrack(unsigned short handle)119     void Animation::destroyNodeTrack(unsigned short handle)
120     {
121         NodeTrackList::iterator i = mNodeTrackList.find(handle);
122 
123         if (i != mNodeTrackList.end())
124         {
125             OGRE_DELETE i->second;
126             mNodeTrackList.erase(i);
127             _keyFrameListChanged();
128         }
129     }
130     //---------------------------------------------------------------------
destroyAllNodeTracks(void)131     void Animation::destroyAllNodeTracks(void)
132     {
133         NodeTrackList::iterator i;
134         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
135         {
136             OGRE_DELETE i->second;
137         }
138         mNodeTrackList.clear();
139         _keyFrameListChanged();
140     }
141     //---------------------------------------------------------------------
createNumericTrack(unsigned short handle)142     NumericAnimationTrack* Animation::createNumericTrack(unsigned short handle)
143     {
144         if (hasNumericTrack(handle))
145         {
146             OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
147                 "Numeric track with the specified handle " +
148                 StringConverter::toString(handle) + " already exists",
149                 "Animation::createNumericTrack");
150         }
151 
152         NumericAnimationTrack* ret = OGRE_NEW NumericAnimationTrack(this, handle);
153 
154         mNumericTrackList[handle] = ret;
155         return ret;
156     }
157     //---------------------------------------------------------------------
createNumericTrack(unsigned short handle,const AnimableValuePtr & anim)158     NumericAnimationTrack* Animation::createNumericTrack(unsigned short handle,
159         const AnimableValuePtr& anim)
160     {
161         NumericAnimationTrack* ret = createNumericTrack(handle);
162 
163         ret->setAssociatedAnimable(anim);
164 
165         return ret;
166     }
167     //---------------------------------------------------------------------
getNumNumericTracks(void) const168     unsigned short Animation::getNumNumericTracks(void) const
169     {
170         return (unsigned short)mNumericTrackList.size();
171     }
172     //---------------------------------------------------------------------
hasNumericTrack(unsigned short handle) const173     bool Animation::hasNumericTrack(unsigned short handle) const
174     {
175         return (mNumericTrackList.find(handle) != mNumericTrackList.end());
176     }
177     //---------------------------------------------------------------------
getNumericTrack(unsigned short handle) const178     NumericAnimationTrack* Animation::getNumericTrack(unsigned short handle) const
179     {
180         NumericTrackList::const_iterator i = mNumericTrackList.find(handle);
181 
182         if (i == mNumericTrackList.end())
183         {
184             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
185                 "Cannot find numeric track with the specified handle " +
186                 StringConverter::toString(handle),
187                 "Animation::getNumericTrack");
188         }
189 
190         return i->second;
191 
192     }
193     //---------------------------------------------------------------------
destroyNumericTrack(unsigned short handle)194     void Animation::destroyNumericTrack(unsigned short handle)
195     {
196         NumericTrackList::iterator i = mNumericTrackList.find(handle);
197 
198         if (i != mNumericTrackList.end())
199         {
200             OGRE_DELETE i->second;
201             mNumericTrackList.erase(i);
202             _keyFrameListChanged();
203         }
204     }
205     //---------------------------------------------------------------------
destroyAllNumericTracks(void)206     void Animation::destroyAllNumericTracks(void)
207     {
208         NumericTrackList::iterator i;
209         for (i = mNumericTrackList.begin(); i != mNumericTrackList.end(); ++i)
210         {
211             OGRE_DELETE i->second;
212         }
213         mNumericTrackList.clear();
214         _keyFrameListChanged();
215     }
216     //---------------------------------------------------------------------
createVertexTrack(unsigned short handle,VertexAnimationType animType)217     VertexAnimationTrack* Animation::createVertexTrack(unsigned short handle,
218         VertexAnimationType animType)
219     {
220         if (hasVertexTrack(handle))
221         {
222             OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
223                 "Vertex track with the specified handle " +
224                 StringConverter::toString(handle) + " already exists",
225                 "Animation::createVertexTrack");
226         }
227 
228         VertexAnimationTrack* ret = OGRE_NEW VertexAnimationTrack(this, handle, animType);
229 
230         mVertexTrackList[handle] = ret;
231         return ret;
232 
233     }
234     //---------------------------------------------------------------------
createVertexTrack(unsigned short handle,VertexData * data,VertexAnimationType animType)235     VertexAnimationTrack* Animation::createVertexTrack(unsigned short handle,
236         VertexData* data, VertexAnimationType animType)
237     {
238         VertexAnimationTrack* ret = createVertexTrack(handle, animType);
239 
240         ret->setAssociatedVertexData(data);
241 
242         return ret;
243     }
244     //---------------------------------------------------------------------
getNumVertexTracks(void) const245     unsigned short Animation::getNumVertexTracks(void) const
246     {
247         return (unsigned short)mVertexTrackList.size();
248     }
249     //---------------------------------------------------------------------
hasVertexTrack(unsigned short handle) const250     bool Animation::hasVertexTrack(unsigned short handle) const
251     {
252         return (mVertexTrackList.find(handle) != mVertexTrackList.end());
253     }
254     //---------------------------------------------------------------------
getVertexTrack(unsigned short handle) const255     VertexAnimationTrack* Animation::getVertexTrack(unsigned short handle) const
256     {
257         VertexTrackList::const_iterator i = mVertexTrackList.find(handle);
258 
259         if (i == mVertexTrackList.end())
260         {
261             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
262                 "Cannot find vertex track with the specified handle " +
263                 StringConverter::toString(handle),
264                 "Animation::getVertexTrack");
265         }
266 
267         return i->second;
268 
269     }
270     //---------------------------------------------------------------------
destroyVertexTrack(unsigned short handle)271     void Animation::destroyVertexTrack(unsigned short handle)
272     {
273         VertexTrackList::iterator i = mVertexTrackList.find(handle);
274 
275         if (i != mVertexTrackList.end())
276         {
277             OGRE_DELETE  i->second;
278             mVertexTrackList.erase(i);
279             _keyFrameListChanged();
280         }
281     }
282     //---------------------------------------------------------------------
destroyAllVertexTracks(void)283     void Animation::destroyAllVertexTracks(void)
284     {
285         VertexTrackList::iterator i;
286         for (i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i)
287         {
288             OGRE_DELETE  i->second;
289         }
290         mVertexTrackList.clear();
291         _keyFrameListChanged();
292     }
293     //---------------------------------------------------------------------
destroyAllTracks(void)294     void Animation::destroyAllTracks(void)
295     {
296         destroyAllNodeTracks();
297         destroyAllNumericTracks();
298         destroyAllVertexTracks();
299     }
300     //---------------------------------------------------------------------
getName(void) const301     const String& Animation::getName(void) const
302     {
303         return mName;
304     }
305     //---------------------------------------------------------------------
apply(Real timePos,Real weight,Real scale)306     void Animation::apply(Real timePos, Real weight, Real scale)
307     {
308         _applyBaseKeyFrame();
309 
310         // Calculate time index for fast keyframe search
311         TimeIndex timeIndex = _getTimeIndex(timePos);
312 
313         NodeTrackList::iterator i;
314         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
315         {
316             i->second->apply(timeIndex, weight, scale);
317         }
318         NumericTrackList::iterator j;
319         for (j = mNumericTrackList.begin(); j != mNumericTrackList.end(); ++j)
320         {
321             j->second->apply(timeIndex, weight, scale);
322         }
323         VertexTrackList::iterator k;
324         for (k = mVertexTrackList.begin(); k != mVertexTrackList.end(); ++k)
325         {
326             k->second->apply(timeIndex, weight, scale);
327         }
328 
329     }
330     //---------------------------------------------------------------------
applyToNode(Node * node,Real timePos,Real weight,Real scale)331     void Animation::applyToNode(Node* node, Real timePos, Real weight, Real scale)
332     {
333         _applyBaseKeyFrame();
334 
335         // Calculate time index for fast keyframe search
336         TimeIndex timeIndex = _getTimeIndex(timePos);
337 
338         NodeTrackList::iterator i;
339         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
340         {
341             i->second->applyToNode(node, timeIndex, weight, scale);
342         }
343     }
344     //---------------------------------------------------------------------
apply(Skeleton * skel,Real timePos,Real weight,Real scale)345     void Animation::apply(Skeleton* skel, Real timePos, Real weight,
346         Real scale)
347     {
348         _applyBaseKeyFrame();
349 
350         // Calculate time index for fast keyframe search
351         TimeIndex timeIndex = _getTimeIndex(timePos);
352 
353         NodeTrackList::iterator i;
354         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
355         {
356             // get bone to apply to
357             Bone* b = skel->getBone(i->first);
358             i->second->applyToNode(b, timeIndex, weight, scale);
359         }
360 
361 
362     }
363     //---------------------------------------------------------------------
apply(Skeleton * skel,Real timePos,float weight,const AnimationState::BoneBlendMask * blendMask,Real scale)364     void Animation::apply(Skeleton* skel, Real timePos, float weight,
365       const AnimationState::BoneBlendMask* blendMask, Real scale)
366     {
367         _applyBaseKeyFrame();
368 
369         // Calculate time index for fast keyframe search
370       TimeIndex timeIndex = _getTimeIndex(timePos);
371 
372       NodeTrackList::iterator i;
373       for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
374       {
375         // get bone to apply to
376         Bone* b = skel->getBone(i->first);
377         i->second->applyToNode(b, timeIndex, (*blendMask)[b->getHandle()] * weight, scale);
378       }
379     }
380     //---------------------------------------------------------------------
apply(Entity * entity,Real timePos,Real weight,bool software,bool hardware)381     void Animation::apply(Entity* entity, Real timePos, Real weight,
382         bool software, bool hardware)
383     {
384         _applyBaseKeyFrame();
385 
386         // Calculate time index for fast keyframe search
387         TimeIndex timeIndex = _getTimeIndex(timePos);
388 
389         VertexTrackList::iterator i;
390         for (i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i)
391         {
392             unsigned short handle = i->first;
393             VertexAnimationTrack* track = i->second;
394 
395             VertexData* swVertexData;
396             VertexData* hwVertexData;
397             if (handle == 0)
398             {
399                 // shared vertex data
400                 swVertexData = entity->_getSoftwareVertexAnimVertexData();
401                 hwVertexData = entity->_getHardwareVertexAnimVertexData();
402                 entity->_markBuffersUsedForAnimation();
403             }
404             else
405             {
406                 // sub entity vertex data (-1)
407                 SubEntity* s = entity->getSubEntity(handle - 1);
408                 // Skip this track if subentity is not visible
409                 if (!s->isVisible())
410                     continue;
411                 swVertexData = s->_getSoftwareVertexAnimVertexData();
412                 hwVertexData = s->_getHardwareVertexAnimVertexData();
413                 s->_markBuffersUsedForAnimation();
414             }
415             // Apply to both hardware and software, if requested
416             if (software)
417             {
418                 track->setTargetMode(VertexAnimationTrack::TM_SOFTWARE);
419                 track->applyToVertexData(swVertexData, timeIndex, weight,
420                     &(entity->getMesh()->getPoseList()));
421             }
422             if (hardware)
423             {
424                 track->setTargetMode(VertexAnimationTrack::TM_HARDWARE);
425                 track->applyToVertexData(hwVertexData, timeIndex, weight,
426                     &(entity->getMesh()->getPoseList()));
427             }
428         }
429 
430     }
431     //---------------------------------------------------------------------
applyToAnimable(const AnimableValuePtr & anim,Real timePos,Real weight,Real scale)432     void Animation::applyToAnimable(const AnimableValuePtr& anim, Real timePos, Real weight, Real scale)
433     {
434         _applyBaseKeyFrame();
435 
436         // Calculate time index for fast keyframe search
437         _getTimeIndex(timePos);
438 
439         NumericTrackList::iterator j;
440         for (j = mNumericTrackList.begin(); j != mNumericTrackList.end(); ++j)
441         {
442             j->second->applyToAnimable(anim, timePos, weight, scale);
443         }
444    }
445     //---------------------------------------------------------------------
applyToVertexData(VertexData * data,Real timePos,Real weight)446     void Animation::applyToVertexData(VertexData* data, Real timePos, Real weight)
447     {
448         _applyBaseKeyFrame();
449 
450         // Calculate time index for fast keyframe search
451         TimeIndex timeIndex = _getTimeIndex(timePos);
452 
453         VertexTrackList::iterator k;
454         for (k = mVertexTrackList.begin(); k != mVertexTrackList.end(); ++k)
455         {
456             k->second->applyToVertexData(data, timeIndex, weight);
457         }
458     }
459     //---------------------------------------------------------------------
setInterpolationMode(InterpolationMode im)460     void Animation::setInterpolationMode(InterpolationMode im)
461     {
462         mInterpolationMode = im;
463     }
464     //---------------------------------------------------------------------
getInterpolationMode(void) const465     Animation::InterpolationMode Animation::getInterpolationMode(void) const
466     {
467         return mInterpolationMode;
468     }
469     //---------------------------------------------------------------------
setDefaultInterpolationMode(InterpolationMode im)470     void Animation::setDefaultInterpolationMode(InterpolationMode im)
471     {
472         msDefaultInterpolationMode = im;
473     }
474     //---------------------------------------------------------------------
getDefaultInterpolationMode(void)475     Animation::InterpolationMode Animation::getDefaultInterpolationMode(void)
476     {
477         return msDefaultInterpolationMode;
478     }
479     //---------------------------------------------------------------------
_getNodeTrackList(void) const480     const Animation::NodeTrackList& Animation::_getNodeTrackList(void) const
481     {
482         return mNodeTrackList;
483 
484     }
485     //---------------------------------------------------------------------
_getNumericTrackList(void) const486     const Animation::NumericTrackList& Animation::_getNumericTrackList(void) const
487     {
488         return mNumericTrackList;
489     }
490     //---------------------------------------------------------------------
_getVertexTrackList(void) const491     const Animation::VertexTrackList& Animation::_getVertexTrackList(void) const
492     {
493         return mVertexTrackList;
494     }
495     //---------------------------------------------------------------------
setRotationInterpolationMode(RotationInterpolationMode im)496     void Animation::setRotationInterpolationMode(RotationInterpolationMode im)
497     {
498         mRotationInterpolationMode = im;
499     }
500     //---------------------------------------------------------------------
getRotationInterpolationMode(void) const501     Animation::RotationInterpolationMode Animation::getRotationInterpolationMode(void) const
502     {
503         return mRotationInterpolationMode;
504     }
505     //---------------------------------------------------------------------
setDefaultRotationInterpolationMode(RotationInterpolationMode im)506     void Animation::setDefaultRotationInterpolationMode(RotationInterpolationMode im)
507     {
508         msDefaultRotationInterpolationMode = im;
509     }
510     //---------------------------------------------------------------------
getDefaultRotationInterpolationMode(void)511     Animation::RotationInterpolationMode Animation::getDefaultRotationInterpolationMode(void)
512     {
513         return msDefaultRotationInterpolationMode;
514     }
515     //---------------------------------------------------------------------
optimise(bool discardIdentityNodeTracks)516     void Animation::optimise(bool discardIdentityNodeTracks)
517     {
518         optimiseNodeTracks(discardIdentityNodeTracks);
519         optimiseVertexTracks();
520 
521     }
522     //-----------------------------------------------------------------------
_collectIdentityNodeTracks(TrackHandleList & tracks) const523     void Animation::_collectIdentityNodeTracks(TrackHandleList& tracks) const
524     {
525         NodeTrackList::const_iterator i, iend;
526         iend = mNodeTrackList.end();
527         for (i = mNodeTrackList.begin(); i != iend; ++i)
528         {
529             const NodeAnimationTrack* track = i->second;
530             if (track->hasNonZeroKeyFrames())
531             {
532                 tracks.erase(i->first);
533             }
534         }
535     }
536     //-----------------------------------------------------------------------
_destroyNodeTracks(const TrackHandleList & tracks)537     void Animation::_destroyNodeTracks(const TrackHandleList& tracks)
538     {
539         TrackHandleList::const_iterator t, tend;
540         tend = tracks.end();
541         for (t = tracks.begin(); t != tend; ++t)
542         {
543             destroyNodeTrack(*t);
544         }
545     }
546     //-----------------------------------------------------------------------
optimiseNodeTracks(bool discardIdentityTracks)547     void Animation::optimiseNodeTracks(bool discardIdentityTracks)
548     {
549         // Iterate over the node tracks and identify those with no useful keyframes
550         std::list<unsigned short> tracksToDestroy;
551         NodeTrackList::iterator i;
552         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
553         {
554             NodeAnimationTrack* track = i->second;
555             if (discardIdentityTracks && !track->hasNonZeroKeyFrames())
556             {
557                 // mark the entire track for destruction
558                 tracksToDestroy.push_back(i->first);
559             }
560             else
561             {
562                 track->optimise();
563             }
564 
565         }
566 
567         // Now destroy the tracks we marked for death
568         for(std::list<unsigned short>::iterator h = tracksToDestroy.begin();
569             h != tracksToDestroy.end(); ++h)
570         {
571             destroyNodeTrack(*h);
572         }
573     }
574     //-----------------------------------------------------------------------
optimiseVertexTracks(void)575     void Animation::optimiseVertexTracks(void)
576     {
577         // Iterate over the node tracks and identify those with no useful keyframes
578         std::list<unsigned short> tracksToDestroy;
579         VertexTrackList::iterator i;
580         for (i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i)
581         {
582             VertexAnimationTrack* track = i->second;
583             if (!track->hasNonZeroKeyFrames())
584             {
585                 // mark the entire track for destruction
586                 tracksToDestroy.push_back(i->first);
587             }
588             else
589             {
590                 track->optimise();
591             }
592 
593         }
594 
595         // Now destroy the tracks we marked for death
596         for(std::list<unsigned short>::iterator h = tracksToDestroy.begin();
597             h != tracksToDestroy.end(); ++h)
598         {
599             destroyVertexTrack(*h);
600         }
601 
602     }
603     //-----------------------------------------------------------------------
clone(const String & newName) const604     Animation* Animation::clone(const String& newName) const
605     {
606         Animation* newAnim = OGRE_NEW Animation(newName, mLength);
607         newAnim->mInterpolationMode = mInterpolationMode;
608         newAnim->mRotationInterpolationMode = mRotationInterpolationMode;
609 
610         // Clone all tracks
611         for (NodeTrackList::const_iterator i = mNodeTrackList.begin();
612             i != mNodeTrackList.end(); ++i)
613         {
614             i->second->_clone(newAnim);
615         }
616         for (NumericTrackList::const_iterator i = mNumericTrackList.begin();
617             i != mNumericTrackList.end(); ++i)
618         {
619             i->second->_clone(newAnim);
620         }
621         for (VertexTrackList::const_iterator i = mVertexTrackList.begin();
622             i != mVertexTrackList.end(); ++i)
623         {
624             i->second->_clone(newAnim);
625         }
626 
627         newAnim->_keyFrameListChanged();
628         return newAnim;
629 
630     }
631     //-----------------------------------------------------------------------
_getTimeIndex(Real timePos) const632     TimeIndex Animation::_getTimeIndex(Real timePos) const
633     {
634         // Uncomment following statement for work as previous
635         //return timePos;
636 
637         // Build keyframe time list on demand
638         if (mKeyFrameTimesDirty)
639         {
640             buildKeyFrameTimeList();
641         }
642 
643         // Wrap time
644         Real totalAnimationLength = mLength;
645 
646         if( timePos > totalAnimationLength && totalAnimationLength > 0.0f )
647             timePos = std::fmod( timePos, totalAnimationLength );
648 
649         // Search for global index
650         KeyFrameTimeList::iterator it =
651             std::lower_bound(mKeyFrameTimes.begin(), mKeyFrameTimes.end(), timePos);
652 
653         return TimeIndex(timePos, static_cast<uint>(std::distance(mKeyFrameTimes.begin(), it)));
654     }
655     //-----------------------------------------------------------------------
buildKeyFrameTimeList(void) const656     void Animation::buildKeyFrameTimeList(void) const
657     {
658         NodeTrackList::const_iterator i;
659         NumericTrackList::const_iterator j;
660         VertexTrackList::const_iterator k;
661 
662         // Clear old keyframe times
663         mKeyFrameTimes.clear();
664 
665         // Collect all keyframe times from each track
666         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
667         {
668             i->second->_collectKeyFrameTimes(mKeyFrameTimes);
669         }
670         for (j = mNumericTrackList.begin(); j != mNumericTrackList.end(); ++j)
671         {
672             j->second->_collectKeyFrameTimes(mKeyFrameTimes);
673         }
674         for (k = mVertexTrackList.begin(); k != mVertexTrackList.end(); ++k)
675         {
676             k->second->_collectKeyFrameTimes(mKeyFrameTimes);
677         }
678 
679         // Build global index to local index map for each track
680         for (i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
681         {
682             i->second->_buildKeyFrameIndexMap(mKeyFrameTimes);
683         }
684         for (j = mNumericTrackList.begin(); j != mNumericTrackList.end(); ++j)
685         {
686             j->second->_buildKeyFrameIndexMap(mKeyFrameTimes);
687         }
688         for (k = mVertexTrackList.begin(); k != mVertexTrackList.end(); ++k)
689         {
690             k->second->_buildKeyFrameIndexMap(mKeyFrameTimes);
691         }
692 
693         // Reset dirty flag
694         mKeyFrameTimesDirty = false;
695     }
696     //-----------------------------------------------------------------------
setUseBaseKeyFrame(bool useBaseKeyFrame,Real keyframeTime,const String & baseAnimName)697     void Animation::setUseBaseKeyFrame(bool useBaseKeyFrame, Real keyframeTime, const String& baseAnimName)
698     {
699         if (useBaseKeyFrame != mUseBaseKeyFrame ||
700             keyframeTime != mBaseKeyFrameTime ||
701             baseAnimName != mBaseKeyFrameAnimationName)
702         {
703             mUseBaseKeyFrame = useBaseKeyFrame;
704             mBaseKeyFrameTime = keyframeTime;
705             mBaseKeyFrameAnimationName = baseAnimName;
706         }
707     }
708     //-----------------------------------------------------------------------
getUseBaseKeyFrame() const709     bool Animation::getUseBaseKeyFrame() const
710     {
711         return mUseBaseKeyFrame;
712     }
713     //-----------------------------------------------------------------------
getBaseKeyFrameTime() const714     Real Animation::getBaseKeyFrameTime() const
715     {
716         return mBaseKeyFrameTime;
717     }
718     //-----------------------------------------------------------------------
getBaseKeyFrameAnimationName() const719     const String& Animation::getBaseKeyFrameAnimationName() const
720     {
721         return mBaseKeyFrameAnimationName;
722     }
723     //-----------------------------------------------------------------------
_applyBaseKeyFrame()724     void Animation::_applyBaseKeyFrame()
725     {
726         if (mUseBaseKeyFrame)
727         {
728             Animation* baseAnim = this;
729             if (!mBaseKeyFrameAnimationName.empty() && mContainer)
730                 baseAnim = mContainer->getAnimation(mBaseKeyFrameAnimationName);
731 
732             if (baseAnim)
733             {
734                 for (NodeTrackList::iterator i = mNodeTrackList.begin(); i != mNodeTrackList.end(); ++i)
735                 {
736                     NodeAnimationTrack* track = i->second;
737 
738                     NodeAnimationTrack* baseTrack;
739                     if (baseAnim == this)
740                         baseTrack = track;
741                     else
742                         baseTrack = baseAnim->getNodeTrack(track->getHandle());
743 
744                     TransformKeyFrame kf(baseTrack, mBaseKeyFrameTime);
745                     baseTrack->getInterpolatedKeyFrame(baseAnim->_getTimeIndex(mBaseKeyFrameTime), &kf);
746                     track->_applyBaseKeyFrame(&kf);
747                 }
748 
749                 for (VertexTrackList::iterator i = mVertexTrackList.begin(); i != mVertexTrackList.end(); ++i)
750                 {
751                     VertexAnimationTrack* track = i->second;
752 
753                     if (track->getAnimationType() == VAT_POSE)
754                     {
755                         VertexAnimationTrack* baseTrack;
756                         if (baseAnim == this)
757                             baseTrack = track;
758                         else
759                             baseTrack = baseAnim->getVertexTrack(track->getHandle());
760 
761                         VertexPoseKeyFrame kf(baseTrack, mBaseKeyFrameTime);
762                         baseTrack->getInterpolatedKeyFrame(baseAnim->_getTimeIndex(mBaseKeyFrameTime), &kf);
763                         track->_applyBaseKeyFrame(&kf);
764 
765                     }
766                 }
767 
768             }
769 
770             // Re-base has been done, this is a one-way translation
771             mUseBaseKeyFrame = false;
772         }
773 
774     }
775     //-----------------------------------------------------------------------
_notifyContainer(AnimationContainer * c)776     void Animation::_notifyContainer(AnimationContainer* c)
777     {
778         mContainer = c;
779     }
780     //-----------------------------------------------------------------------
getContainer()781     AnimationContainer* Animation::getContainer()
782     {
783         return mContainer;
784     }
785 
786 
787 }
788 
789 
790