Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreAnimationTrack.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

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