source: OGRE/trunk/ogrenew/OgreMain/src/OgreAnimationTrack.cpp @ 657

Revision 657, 15.8 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreAnimationTrack.h"
27#include "OgreAnimation.h"
28#include "OgreKeyFrame.h"
29#include "OgreNode.h"
30#include "OgreLogManager.h"
31
32// Debug
33#include "OgreRenderWindow.h"
34#include "OgreRoot.h"
35Ogre::RenderWindow* mMainWindow = 0;
36// End Debug
37
38namespace Ogre {
39
40    //---------------------------------------------------------------------
41    AnimationTrack::AnimationTrack(Animation* parent) : mParent(parent)
42    {
43        mTargetNode = 0;
44        mMaxKeyFrameTime = -1;
45        mSplineBuildNeeded = false;
46                mUseShortestRotationPath = true ;
47    }
48    //---------------------------------------------------------------------
49    AnimationTrack::AnimationTrack(Animation* parent, Node* targetNode)
50        : mParent(parent), mTargetNode(targetNode)
51    {
52        mMaxKeyFrameTime = -1;
53        mSplineBuildNeeded = false;
54                mUseShortestRotationPath = true ;
55    }
56    //---------------------------------------------------------------------
57    AnimationTrack::~AnimationTrack()
58    {
59        removeAllKeyFrames();
60    }
61    //---------------------------------------------------------------------
62    unsigned short AnimationTrack::getNumKeyFrames(void) const
63    {
64        return (unsigned short)mKeyFrames.size();
65    }
66    //---------------------------------------------------------------------
67    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    //---------------------------------------------------------------------
75    Real AnimationTrack::getKeyFramesAtTime(Real timePos, KeyFrame** keyFrame1, KeyFrame** keyFrame2,
76            unsigned short* firstKeyIndex) const
77    {
78        short firstIndex = -1;
79        Real totalAnimationLength = mParent->getLength();
80
81        // Wrap time
82        while (timePos > totalAnimationLength)
83        {
84            timePos -= totalAnimationLength;
85        }
86
87        KeyFrameList::const_iterator i = mKeyFrames.begin();
88        // Find last keyframe before or on current time
89        while (i != mKeyFrames.end() && (*i)->getTime() <= timePos)
90        {
91            *keyFrame1 = *i++;
92            ++firstIndex;
93        }
94
95        // Trap case where there is no key before this time (problem with animation config)
96        // In this case use the first key anyway and pretend it's time index 0
97        if (firstIndex == -1)
98        {
99            *keyFrame1 = *i;
100            ++firstIndex;
101        }
102
103        // Fill index of the first key
104        if (firstKeyIndex != NULL)
105        {
106            *firstKeyIndex = firstIndex;
107        }
108
109        // Parametric time
110        // t1 = time of previous keyframe
111        // t2 = time of next keyframe
112        Real t1, t2;
113        // Find first keyframe after the time
114        // If no next keyframe, wrap back to first
115        if (i == mKeyFrames.end())
116        {
117            *keyFrame2 = mKeyFrames[0];
118            t2 = totalAnimationLength;
119        }
120        else
121        {
122            *keyFrame2 = *i;
123            t2 = (*keyFrame2)->getTime();
124        }
125
126        t1 = (*keyFrame1)->getTime();
127
128        if (t1 == t2)
129        {
130            // Same KeyFrame (only one)
131            return 0.0;
132        }
133        else
134        {
135            return (timePos - t1) / (t2 - t1);
136        }
137    }
138    //---------------------------------------------------------------------
139    KeyFrame* AnimationTrack::createKeyFrame(Real timePos)
140    {
141        KeyFrame* kf = new KeyFrame(this, timePos);
142
143        // Insert at correct location
144        if (timePos > mMaxKeyFrameTime || (timePos == 0 && mKeyFrames.empty()))
145        {
146            // Quick insert at end
147            mKeyFrames.push_back(kf);
148            mMaxKeyFrameTime = timePos;
149        }
150        else
151        {
152            // Search
153            KeyFrameList::iterator i = mKeyFrames.begin();
154            while ((*i)->getTime() < timePos && i != mKeyFrames.end())
155            {
156                ++i;
157            }
158            mKeyFrames.insert(i, kf);
159        }
160
161        _keyFrameDataChanged();
162
163        return kf;
164
165    }
166    //---------------------------------------------------------------------
167    void AnimationTrack::removeKeyFrame(unsigned short index)
168    {
169                // If you hit this assert, then the keyframe index is out of bounds
170        assert( index < (ushort)mKeyFrames.size() );
171
172        KeyFrameList::iterator i = mKeyFrames.begin();
173
174        i += index;
175
176        delete *i;
177
178        mKeyFrames.erase(i);
179
180        _keyFrameDataChanged();
181
182
183    }
184    //---------------------------------------------------------------------
185    void AnimationTrack::removeAllKeyFrames(void)
186    {
187        KeyFrameList::iterator i = mKeyFrames.begin();
188
189        for (; i != mKeyFrames.end(); ++i)
190        {
191            delete *i;
192        }
193
194        _keyFrameDataChanged();
195
196        mKeyFrames.clear();
197
198    }
199    //---------------------------------------------------------------------
200    KeyFrame AnimationTrack::getInterpolatedKeyFrame(Real timeIndex) const
201    {
202        // Return value (note unattached)
203        KeyFrame kret(0, timeIndex);
204       
205        // Keyframe pointers
206        KeyFrame *k1, *k2;
207        unsigned short firstKeyIndex;
208
209        Real t = this->getKeyFramesAtTime(timeIndex, &k1, &k2, &firstKeyIndex);
210
211        if (t == 0.0)
212        {
213            // Just use k1
214            kret.setRotation(k1->getRotation());
215            kret.setTranslate(k1->getTranslate());
216            kret.setScale(k1->getScale());
217        }
218        else
219        {
220            // Interpolate by t
221            Animation::InterpolationMode im = mParent->getInterpolationMode();
222            Animation::RotationInterpolationMode rim =
223                mParent->getRotationInterpolationMode();
224            Vector3 base;
225            switch(im)
226            {
227            case Animation::IM_LINEAR:
228                // Interpolate linearly
229                // Rotation
230                // Interpolate to nearest rotation if mUseShortestRotationPath set
231                if (rim == Animation::RIM_LINEAR)
232                {
233                    kret.setRotation( Quaternion::nlerp(t, k1->getRotation(),
234                        k2->getRotation(), mUseShortestRotationPath) );
235                }
236                else //if (rim == Animation::RIM_SPHERICAL)
237                {
238                    kret.setRotation( Quaternion::Slerp(t, k1->getRotation(),
239                                            k2->getRotation(), mUseShortestRotationPath) );
240                }
241
242                // Translation
243                base = k1->getTranslate();
244                kret.setTranslate( base + ((k2->getTranslate() - base) * t) );
245
246                // Scale
247                base = k1->getScale();
248                kret.setScale( base + ((k2->getScale() - base) * t) );
249                break;
250
251            case Animation::IM_SPLINE:
252                // Spline interpolation
253
254                // Build splines if required
255                if (mSplineBuildNeeded)
256                {
257                    buildInterpolationSplines();
258                }
259
260                // Rotation, take mUseShortestRotationPath into account
261                kret.setRotation( mRotationSpline.interpolate(firstKeyIndex, t,
262                                        mUseShortestRotationPath) );
263
264                // Translation
265                kret.setTranslate( mPositionSpline.interpolate(firstKeyIndex, t) );
266
267                // Scale
268                kret.setScale( mScaleSpline.interpolate(firstKeyIndex, t) );
269
270                break;
271            }
272
273        }
274       
275        return kret;
276       
277    }
278    //---------------------------------------------------------------------
279    void AnimationTrack::apply(Real timePos, Real weight, bool accumulate,
280                Real scale)
281    {
282        applyToNode(mTargetNode, timePos, weight, accumulate, scale);
283       
284    }
285    //---------------------------------------------------------------------
286    Node* AnimationTrack::getAssociatedNode(void) const
287    {
288        return mTargetNode;
289    }
290    //---------------------------------------------------------------------
291    void AnimationTrack::setAssociatedNode(Node* node)
292    {
293        mTargetNode = node;
294    }
295    //---------------------------------------------------------------------
296    void AnimationTrack::applyToNode(Node* node, Real timePos, Real weight,
297                bool accumulate, Real scl)
298    {
299        KeyFrame kf = this->getInterpolatedKeyFrame(timePos);
300                if (accumulate)
301        {
302            // add to existing. Weights are not relative, but treated as absolute multipliers for the animation
303            Vector3 translate = kf.getTranslate() * weight * scl;
304                        node->translate(translate);
305
306                        // interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full
307            Quaternion rotate;
308            Animation::RotationInterpolationMode rim =
309                mParent->getRotationInterpolationMode();
310            if (rim == Animation::RIM_LINEAR)
311            {
312                rotate = Quaternion::nlerp(weight, Quaternion::IDENTITY, kf.getRotation());
313            }
314            else //if (rim == Animation::RIM_SPHERICAL)
315            {
316                rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation());
317            }
318                        node->rotate(rotate);
319
320                        Vector3 scale = kf.getScale();
321                        // Not sure how to modify scale for cumulative anims... leave it alone
322                        //scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE;
323                        if (scl != 1.0f && scale != Vector3::UNIT_SCALE)
324                        {
325                                scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * scl;
326                        }
327                        node->scale(scale);
328                }
329        else
330        {
331                        // apply using weighted transform method
332                        Vector3 scale = kf.getScale();
333                        if (scl != 1.0f && scale != Vector3::UNIT_SCALE)
334                        {
335                                scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * scl;
336                        }
337                        node->_weightedTransform(weight, kf.getTranslate() * scl, kf.getRotation(),
338                                scale);
339                }
340
341        /*
342        // DEBUG
343        if (!mMainWindow)
344        {
345            mMainWindow = Root::getSingleton().getRenderWindow("OGRE Render Window");
346        }
347        String msg = "Time: ";
348        msg << timePos;
349        mMainWindow->setDebugText(msg);
350        */
351
352        //node->rotate(kf.getRotation() * weight);
353        //node->translate(kf.getTranslate() * weight);
354
355
356
357
358    }
359    //---------------------------------------------------------------------
360    void AnimationTrack::buildInterpolationSplines(void) const
361    {
362        // Don't calc automatically, do it on request at the end
363        mPositionSpline.setAutoCalculate(false);
364        mRotationSpline.setAutoCalculate(false);
365        mScaleSpline.setAutoCalculate(false);
366
367        mPositionSpline.clear();
368        mRotationSpline.clear();
369        mScaleSpline.clear();
370
371        KeyFrameList::const_iterator i, iend;
372        iend = mKeyFrames.end(); // precall to avoid overhead
373        for (i = mKeyFrames.begin(); i != iend; ++i)
374        {
375            mPositionSpline.addPoint((*i)->getTranslate());
376            mRotationSpline.addPoint((*i)->getRotation());
377            mScaleSpline.addPoint((*i)->getScale());
378        }
379
380        mPositionSpline.recalcTangents();
381        mRotationSpline.recalcTangents();
382        mScaleSpline.recalcTangents();
383
384
385        mSplineBuildNeeded = false;
386    }
387       
388    //---------------------------------------------------------------------
389        void AnimationTrack::setUseShortestRotationPath(bool useShortestPath)
390        {
391                mUseShortestRotationPath = useShortestPath ;
392        }
393       
394    //---------------------------------------------------------------------
395        bool AnimationTrack::getUseShortestRotationPath() const
396        {
397                return mUseShortestRotationPath ;
398        }
399    //---------------------------------------------------------------------
400    void AnimationTrack::_keyFrameDataChanged(void) const
401    {
402        mSplineBuildNeeded = true;
403    }
404    //---------------------------------------------------------------------
405        bool AnimationTrack::hasNonZeroKeyFrames(void) const
406        {
407        KeyFrameList::const_iterator i = mKeyFrames.begin();
408        for (; i != mKeyFrames.end(); ++i)
409        {
410                        // look for keyframes which have any component which is non-zero
411                        // Since exporters can be a little inaccurate sometimes we use a
412                        // tolerance value rather than looking for nothing
413                        KeyFrame* kf = *i;
414                        Vector3 trans = kf->getTranslate();
415                        Vector3 scale = kf->getScale();
416                        Vector3 axis;
417                        Radian angle;
418                        kf->getRotation().ToAngleAxis(angle, axis);
419                        Real tolerance = 1e-3f;
420                        if (!trans.positionEquals(Vector3::ZERO, tolerance) ||
421                                !scale.positionEquals(Vector3::UNIT_SCALE, tolerance) ||
422                                !Math::RealEqual(angle.valueRadians(), 0.0f, tolerance))
423                        {
424                                return true;
425                        }
426                       
427                }
428
429                return false;
430        }
431    //---------------------------------------------------------------------
432        void AnimationTrack::optimise(void)
433        {
434                // Eliminate duplicate keyframes from 2nd to penultimate keyframe
435                // NB only eliminate middle keys from sequences of 5+ identical keyframes
436                // since we need to preserve the boundary keys in place, and we need
437                // 2 at each end to preserve tangents for spline interpolation
438                Vector3 lasttrans;
439                Vector3 lastscale;
440                Quaternion lastorientation;
441        KeyFrameList::iterator i = mKeyFrames.begin();
442                Radian quatTolerance(1e-3f);
443                std::list<unsigned short> removeList;
444                unsigned short k = 0;
445                ushort dupKfCount = 0;
446        for (; i != mKeyFrames.end(); ++i, ++k)
447        {
448                        KeyFrame* kf = *i;
449                        Vector3 newtrans = kf->getTranslate();
450                        Vector3 newscale = kf->getScale();
451                        Quaternion neworientation = kf->getRotation();
452                        // Ignore first keyframe; now include the last keyframe as we eliminate
453                        // only k-2 in a group of 5 to ensure we only eliminate middle keys
454                        if (i != mKeyFrames.begin() &&
455                                newtrans.positionEquals(lasttrans) &&
456                                newscale.positionEquals(lastscale) &&
457                                neworientation.equals(lastorientation, quatTolerance))
458                        {
459                                ++dupKfCount;
460
461                                // 4 indicates this is the 5th duplicate keyframe
462                                if (dupKfCount == 4)
463                                {
464                                        // remove the 'middle' keyframe
465                                        removeList.push_back(k-2);     
466                                        --dupKfCount;
467                                }
468                        }
469                        else
470                        {
471                                // reset
472                                dupKfCount = 0;
473                                lasttrans = newtrans;
474                                lastscale = newscale;
475                                lastorientation = neworientation;
476                        }
477                }
478
479                // Now remove keyframes, in reverse order to avoid index revocation
480                std::list<unsigned short>::reverse_iterator r = removeList.rbegin();
481                for (; r!= removeList.rend(); ++r)
482                {
483                        removeKeyFrame(*r);
484                }
485                       
486                       
487        }
488       
489}
490
Note: See TracBrowser for help on using the repository browser.