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