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(this, 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 _keyFrameDataChanged(); 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 _keyFrameDataChanged(); 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 _keyFrameDataChanged(); 00195 00196 mKeyFrames.clear(); 00197 00198 } 00199 //--------------------------------------------------------------------- 00200 KeyFrame AnimationTrack::getInterpolatedKeyFrame(Real timeIndex) const 00201 { 00202 // Return value (note unattached) 00203 KeyFrame kret(0, 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 Animation::RotationInterpolationMode rim = 00223 mParent->getRotationInterpolationMode(); 00224 Vector3 base; 00225 switch(im) 00226 { 00227 case Animation::IM_LINEAR: 00228 // Interpolate linearly 00229 // Rotation 00230 // Interpolate to nearest rotation if mUseShortestRotationPath set 00231 if (rim == Animation::RIM_LINEAR) 00232 { 00233 kret.setRotation( Quaternion::nlerp(t, k1->getRotation(), 00234 k2->getRotation(), mUseShortestRotationPath) ); 00235 } 00236 else //if (rim == Animation::RIM_SPHERICAL) 00237 { 00238 kret.setRotation( Quaternion::Slerp(t, k1->getRotation(), 00239 k2->getRotation(), mUseShortestRotationPath) ); 00240 } 00241 00242 // Translation 00243 base = k1->getTranslate(); 00244 kret.setTranslate( base + ((k2->getTranslate() - base) * t) ); 00245 00246 // Scale 00247 base = k1->getScale(); 00248 kret.setScale( base + ((k2->getScale() - base) * t) ); 00249 break; 00250 00251 case Animation::IM_SPLINE: 00252 // Spline interpolation 00253 00254 // Build splines if required 00255 if (mSplineBuildNeeded) 00256 { 00257 buildInterpolationSplines(); 00258 } 00259 00260 // Rotation, take mUseShortestRotationPath into account 00261 kret.setRotation( mRotationSpline.interpolate(firstKeyIndex, t, 00262 mUseShortestRotationPath) ); 00263 00264 // Translation 00265 kret.setTranslate( mPositionSpline.interpolate(firstKeyIndex, t) ); 00266 00267 // Scale 00268 kret.setScale( mScaleSpline.interpolate(firstKeyIndex, t) ); 00269 00270 break; 00271 } 00272 00273 } 00274 00275 return kret; 00276 00277 } 00278 //--------------------------------------------------------------------- 00279 void AnimationTrack::apply(Real timePos, Real weight, bool accumulate) 00280 { 00281 applyToNode(mTargetNode, timePos, weight, accumulate); 00282 00283 } 00284 //--------------------------------------------------------------------- 00285 Node* AnimationTrack::getAssociatedNode(void) const 00286 { 00287 return mTargetNode; 00288 } 00289 //--------------------------------------------------------------------- 00290 void AnimationTrack::setAssociatedNode(Node* node) 00291 { 00292 mTargetNode = node; 00293 } 00294 //--------------------------------------------------------------------- 00295 void AnimationTrack::applyToNode(Node* node, Real timePos, Real weight, bool accumulate) 00296 { 00297 KeyFrame kf = this->getInterpolatedKeyFrame(timePos); 00298 if (accumulate) 00299 { 00300 // add to existing. Weights are not relative, but treated as absolute multipliers for the animation 00301 Vector3 translate = kf.getTranslate() * weight; 00302 node->translate(translate); 00303 00304 // interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full 00305 Quaternion rotate; 00306 Animation::RotationInterpolationMode rim = 00307 mParent->getRotationInterpolationMode(); 00308 if (rim == Animation::RIM_LINEAR) 00309 { 00310 rotate = Quaternion::nlerp(weight, Quaternion::IDENTITY, kf.getRotation()); 00311 } 00312 else //if (rim == Animation::RIM_SPHERICAL) 00313 { 00314 rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation()); 00315 } 00316 node->rotate(rotate); 00317 00318 Vector3 scale = kf.getScale(); 00319 // Not sure how to modify scale for cumulative anims... leave it alone 00320 //scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE; 00321 node->scale(scale); 00322 } 00323 else 00324 { 00325 // apply using weighted transform method 00326 node->_weightedTransform(weight, kf.getTranslate(), kf.getRotation(), 00327 kf.getScale()); 00328 } 00329 00330 /* 00331 // DEBUG 00332 if (!mMainWindow) 00333 { 00334 mMainWindow = Root::getSingleton().getRenderWindow("OGRE Render Window"); 00335 } 00336 String msg = "Time: "; 00337 msg << timePos; 00338 mMainWindow->setDebugText(msg); 00339 */ 00340 00341 //node->rotate(kf.getRotation() * weight); 00342 //node->translate(kf.getTranslate() * weight); 00343 00344 00345 00346 00347 } 00348 //--------------------------------------------------------------------- 00349 void AnimationTrack::buildInterpolationSplines(void) const 00350 { 00351 // Don't calc automatically, do it on request at the end 00352 mPositionSpline.setAutoCalculate(false); 00353 mRotationSpline.setAutoCalculate(false); 00354 mScaleSpline.setAutoCalculate(false); 00355 00356 mPositionSpline.clear(); 00357 mRotationSpline.clear(); 00358 mScaleSpline.clear(); 00359 00360 KeyFrameList::const_iterator i, iend; 00361 iend = mKeyFrames.end(); // precall to avoid overhead 00362 for (i = mKeyFrames.begin(); i != iend; ++i) 00363 { 00364 mPositionSpline.addPoint((*i)->getTranslate()); 00365 mRotationSpline.addPoint((*i)->getRotation()); 00366 mScaleSpline.addPoint((*i)->getScale()); 00367 } 00368 00369 mPositionSpline.recalcTangents(); 00370 mRotationSpline.recalcTangents(); 00371 mScaleSpline.recalcTangents(); 00372 00373 00374 mSplineBuildNeeded = false; 00375 } 00376 00377 //--------------------------------------------------------------------- 00378 void AnimationTrack::setUseShortestRotationPath(bool useShortestPath) 00379 { 00380 mUseShortestRotationPath = useShortestPath ; 00381 } 00382 00383 //--------------------------------------------------------------------- 00384 bool AnimationTrack::getUseShortestRotationPath() const 00385 { 00386 return mUseShortestRotationPath ; 00387 } 00388 //--------------------------------------------------------------------- 00389 void AnimationTrack::_keyFrameDataChanged(void) const 00390 { 00391 mSplineBuildNeeded = true; 00392 } 00393 00394 } 00395
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:14 2004