Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreAnimationTrack.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreAnimationTrack.h"
00027 #include "OgreAnimation.h"
00028 #include "OgreKeyFrame.h"
00029 #include "OgreNode.h"
00030 #include "OgreLogManager.h"
00031 
00032 // Debug
00033 #include "OgreRenderWindow.h"
00034 #include "OgreRoot.h"
00035 Ogre::RenderWindow* mMainWindow = 0;
00036 // End Debug
00037 
00038 namespace Ogre {
00039 
00040     //---------------------------------------------------------------------
00041     AnimationTrack::AnimationTrack(Animation* parent) : mParent(parent)
00042     {
00043         mTargetNode = 0;
00044         mMaxKeyFrameTime = -1;
00045         mSplineBuildNeeded = false;
00046         mUseShortestRotationPath = true ;
00047     }
00048     //---------------------------------------------------------------------
00049     AnimationTrack::AnimationTrack(Animation* parent, Node* targetNode) 
00050         : mParent(parent), mTargetNode(targetNode)
00051     {
00052         mMaxKeyFrameTime = -1;
00053         mSplineBuildNeeded = false;
00054         mUseShortestRotationPath = true ;
00055     }
00056     //---------------------------------------------------------------------
00057     AnimationTrack::~AnimationTrack()
00058     {
00059         removeAllKeyFrames();
00060     }
00061     //---------------------------------------------------------------------
00062     unsigned short AnimationTrack::getNumKeyFrames(void) const
00063     {
00064         return (unsigned short)mKeyFrames.size();
00065     }
00066     //---------------------------------------------------------------------
00067     KeyFrame* AnimationTrack::getKeyFrame(unsigned short index) const
00068     {
00069         // If you hit this assert, then the keyframe index is out of bounds
00070         assert( index < (ushort)mKeyFrames.size() );
00071 
00072         return mKeyFrames[index];
00073     }
00074     //---------------------------------------------------------------------
00075     Real AnimationTrack::getKeyFramesAtTime(Real timePos, KeyFrame** keyFrame1, KeyFrame** keyFrame2,
00076             unsigned short* firstKeyIndex) const
00077     {
00078         short firstIndex = -1;
00079         Real totalAnimationLength = mParent->getLength();
00080 
00081         // Wrap time 
00082         while (timePos > totalAnimationLength)
00083         {
00084             timePos -= totalAnimationLength;
00085         }
00086 
00087         KeyFrameList::const_iterator i = mKeyFrames.begin();
00088         // Find last keyframe before or on current time
00089         while (i != mKeyFrames.end() && (*i)->getTime() <= timePos)
00090         {
00091             *keyFrame1 = *i++;
00092             ++firstIndex;
00093         }
00094 
00095         // Trap case where there is no key before this time (problem with animation config)
00096         // In this case use the first key anyway and pretend it's time index 0
00097         if (firstIndex == -1)
00098         {
00099             *keyFrame1 = *i;
00100             ++firstIndex;
00101         }
00102 
00103         // Fill index of the first key
00104         if (firstKeyIndex != NULL)
00105         {
00106             *firstKeyIndex = firstIndex;
00107         }
00108 
00109         // Parametric time
00110         // t1 = time of previous keyframe
00111         // t2 = time of next keyframe 
00112         Real t1, t2;
00113         // Find first keyframe after the time
00114         // If no next keyframe, wrap back to first
00115         if (i == mKeyFrames.end())
00116         {
00117             *keyFrame2 = mKeyFrames[0];
00118             t2 = totalAnimationLength;
00119         }
00120         else
00121         {
00122             *keyFrame2 = *i;
00123             t2 = (*keyFrame2)->getTime();
00124         }
00125 
00126         t1 = (*keyFrame1)->getTime();
00127 
00128         if (t1 == t2)
00129         {
00130             // Same KeyFrame (only one)
00131             return 0.0;
00132         }
00133         else
00134         {
00135             return (timePos - t1) / (t2 - t1);
00136         }
00137     }
00138     //---------------------------------------------------------------------
00139     KeyFrame* AnimationTrack::createKeyFrame(Real timePos)
00140     {
00141         KeyFrame* kf = new KeyFrame(timePos);
00142 
00143         // Insert at correct location
00144         if (timePos > mMaxKeyFrameTime || (timePos == 0 && mKeyFrames.empty()))
00145         {
00146             // Quick insert at end
00147             mKeyFrames.push_back(kf);
00148             mMaxKeyFrameTime = timePos;
00149         }
00150         else
00151         {
00152             // Search 
00153             KeyFrameList::iterator i = mKeyFrames.begin();
00154             while ((*i)->getTime() > timePos && i != mKeyFrames.end())
00155             {
00156                 ++i;
00157             }
00158             mKeyFrames.insert(i, kf);
00159         }
00160 
00161         mSplineBuildNeeded = true;
00162 
00163         return kf;
00164 
00165     }
00166     //---------------------------------------------------------------------
00167     void AnimationTrack::removeKeyFrame(unsigned short index)
00168     {
00169         // If you hit this assert, then the keyframe index is out of bounds
00170         assert( index < (ushort)mKeyFrames.size() );
00171 
00172         KeyFrameList::iterator i = mKeyFrames.begin();
00173 
00174         i += index;
00175 
00176         delete *i;
00177 
00178         mKeyFrames.erase(i);
00179 
00180         mSplineBuildNeeded = true;
00181 
00182 
00183     }
00184     //---------------------------------------------------------------------
00185     void AnimationTrack::removeAllKeyFrames(void)
00186     {
00187         KeyFrameList::iterator i = mKeyFrames.begin();
00188 
00189         for (; i != mKeyFrames.end(); ++i)
00190         {
00191             delete *i;
00192         }
00193 
00194         mSplineBuildNeeded = true;
00195 
00196         mKeyFrames.clear();
00197 
00198     }
00199     //---------------------------------------------------------------------
00200     KeyFrame AnimationTrack::getInterpolatedKeyFrame(Real timeIndex) const
00201     {
00202         // Return value
00203         KeyFrame kret(timeIndex);
00204         
00205         // Keyframe pointers
00206         KeyFrame *k1, *k2;
00207         unsigned short firstKeyIndex;
00208 
00209         Real t = this->getKeyFramesAtTime(timeIndex, &k1, &k2, &firstKeyIndex);
00210 
00211         if (t == 0.0)
00212         {
00213             // Just use k1
00214             kret.setRotation(k1->getRotation());
00215             kret.setTranslate(k1->getTranslate());
00216             kret.setScale(k1->getScale());
00217         }
00218         else
00219         {
00220             // Interpolate by t
00221             Animation::InterpolationMode im = mParent->getInterpolationMode();
00222             Vector3 base;
00223             switch(im)
00224             {
00225             case Animation::IM_LINEAR:
00226                 // Interpolate linearly
00227                 // Rotation
00228                 // Interpolate to nearest rotation if mUseShortestRotationPath set
00229                 kret.setRotation( Quaternion::Slerp(t, k1->getRotation(), 
00230                     k2->getRotation(), mUseShortestRotationPath) );
00231 
00232                 // Translation
00233                 base = k1->getTranslate();
00234                 kret.setTranslate( base + ((k2->getTranslate() - base) * t) );
00235 
00236                 // Scale
00237                 base = k1->getScale();
00238                 kret.setScale( base + ((k2->getScale() - base) * t) );
00239                 break;
00240 
00241             case Animation::IM_SPLINE:
00242                 // Spline interpolation
00243 
00244                 // Build splines if required
00245                 if (mSplineBuildNeeded)
00246                 {
00247                     buildInterpolationSplines();
00248                 }
00249 
00250                 // Rotation, take mUseShortestRotationPath into account
00251                 kret.setRotation( mRotationSpline.interpolate(firstKeyIndex, t, 
00252                     mUseShortestRotationPath) );
00253 
00254                 // Translation
00255                 kret.setTranslate( mPositionSpline.interpolate(firstKeyIndex, t) );
00256 
00257                 // Scale
00258                 kret.setScale( mScaleSpline.interpolate(firstKeyIndex, t) );
00259 
00260                 break;
00261             }
00262 
00263         }
00264         
00265         return kret;
00266         
00267     }
00268     //---------------------------------------------------------------------
00269     void AnimationTrack::apply(Real timePos, Real weight, bool accumulate)
00270     {
00271         applyToNode(mTargetNode, timePos, weight, accumulate);
00272         
00273     }
00274     //---------------------------------------------------------------------
00275     Node* AnimationTrack::getAssociatedNode(void) const
00276     {
00277         return mTargetNode;
00278     }
00279     //---------------------------------------------------------------------
00280     void AnimationTrack::setAssociatedNode(Node* node)
00281     {
00282         mTargetNode = node;
00283     }
00284     //---------------------------------------------------------------------
00285     void AnimationTrack::applyToNode(Node* node, Real timePos, Real weight, bool accumulate)
00286     {
00287         KeyFrame kf = this->getInterpolatedKeyFrame(timePos);
00288         if (accumulate) 
00289         {
00290             // add to existing. Weights are not relative, but treated as absolute multipliers for the animation
00291             Vector3 translate = kf.getTranslate() * weight;
00292             node->translate(translate);
00293 
00294             // interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full
00295             Quaternion rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation());
00296             node->rotate(rotate);
00297 
00298             Vector3 scale = kf.getScale();
00299             // Not sure how to modify scale for cumulative anims... leave it alone
00300             //scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE;
00301             node->scale(scale);
00302         } 
00303         else 
00304         {
00305             // apply using weighted transform method
00306             node->_weightedTransform(weight, kf.getTranslate(), kf.getRotation(),
00307                 kf.getScale());
00308         }
00309 
00310         /*
00311         // DEBUG
00312         if (!mMainWindow)
00313         {
00314             mMainWindow = Root::getSingleton().getRenderWindow("OGRE Render Window");
00315         }
00316         String msg = "Time: ";
00317         msg << timePos;
00318         mMainWindow->setDebugText(msg);
00319         */
00320 
00321         //node->rotate(kf.getRotation() * weight);
00322         //node->translate(kf.getTranslate() * weight);
00323 
00324 
00325 
00326 
00327     }
00328     //---------------------------------------------------------------------
00329     void AnimationTrack::buildInterpolationSplines(void) const
00330     {
00331         // Don't calc automatically, do it on request at the end
00332         mPositionSpline.setAutoCalculate(false);
00333         mRotationSpline.setAutoCalculate(false);
00334         mScaleSpline.setAutoCalculate(false);
00335 
00336         mPositionSpline.clear();
00337         mRotationSpline.clear();
00338         mScaleSpline.clear();
00339 
00340         KeyFrameList::const_iterator i, iend;
00341         iend = mKeyFrames.end(); // precall to avoid overhead
00342         for (i = mKeyFrames.begin(); i != iend; ++i)
00343         {
00344             mPositionSpline.addPoint((*i)->getTranslate());
00345             mRotationSpline.addPoint((*i)->getRotation());
00346             mScaleSpline.addPoint((*i)->getScale());
00347         }
00348 
00349         mPositionSpline.recalcTangents();
00350         mRotationSpline.recalcTangents();
00351         mScaleSpline.recalcTangents();
00352 
00353 
00354         mSplineBuildNeeded = false;
00355     }
00356     
00357     //---------------------------------------------------------------------
00358     void AnimationTrack::setUseShortestRotationPath(bool useShortestPath)
00359     {
00360         mUseShortestRotationPath = useShortestPath ;
00361     }
00362     
00363     //---------------------------------------------------------------------
00364     bool AnimationTrack::getUseShortestRotationPath() const
00365     {
00366         return mUseShortestRotationPath ;
00367     }
00368     
00369 }
00370 

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:01 2004