diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7b166ba91a..5598e0e56f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -113,7 +113,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", loop); + mAnimation->play(mCurrentGroup, "stop", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) @@ -152,7 +152,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); } else if(mAnimQueue.size() > 0) { @@ -160,7 +160,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", false); + mAnimation->play(mCurrentGroup, "start", "stop", false); } } return; @@ -247,7 +247,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); } else if(mode == 0) { @@ -283,7 +283,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 160641eb0a..1dd46365bc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) + , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -293,12 +294,12 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::reset(const std::string &marker) +void Animation::reset(const std::string &start, const std::string &stop) { mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) - mNextKey++; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) + mNextKey++; if(mNextKey != mCurrentKeys->end()) mCurrentTime = mNextKey->first; else @@ -307,6 +308,17 @@ void Animation::reset(const std::string &marker) mCurrentTime = 0.0f; } + if(stop.length() > 0) + { + NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; + while(stopKey != mCurrentKeys->end() && stopKey->second != stop) + stopKey++; + if(stopKey != mCurrentKeys->end()) + mStopTime = stopKey->first; + else + mStopTime = mCurrentAnim->getLength(); + } + if(mNonAccumRoot) { const Ogre::NodeAnimationTrack *track = 0; @@ -328,7 +340,7 @@ void Animation::reset(const std::string &marker) } -void Animation::play(const std::string &groupname, const std::string &start, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { bool found = false; @@ -351,9 +363,9 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start); + reset(start, stop); + setLooping(loop); mPlaying = true; - mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() <end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); + mPlaying = (mLooping || mStopTime > targetTime); break; } @@ -380,6 +392,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mNextKey++; movement += updatePosition(time); + mPlaying = (mLooping || mStopTime > time); + timepassed = targetTime - time; if(evt == "start" || evt == "loop start") @@ -391,7 +405,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; } @@ -401,17 +415,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; + continue; } - else - { - mPlaying = false; - if(mController) - mController->markerEvent(time, evt); - } - continue; + // fall-through } if(mController) mController->markerEvent(time, evt); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 130805a506..47bc8c3900 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,6 +33,7 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; float mCurrentTime; + float mStopTime; bool mPlaying; bool mLooping; @@ -53,9 +54,11 @@ protected: * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Resets the animation to the time of the specified marker, without moving - * anything. If the marker is not found, it resets to the beginning. */ - void reset(const std::string &marker); + /* Resets the animation to the time of the specified start marker, without + * moving anything, and set the end time to the specified stop marker. If + * the marker is not found, it resets to the beginning or end respectively. + */ + void reset(const std::string &start, const std::string &stop); /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); @@ -86,7 +89,7 @@ public: void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 9f8962d7c3..36cac2155d 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,7 +145,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->play("inventoryhandtohand", "start", "stop", false); } // --------------------------------------------------------------------------------------------------