diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4684ca6ea7..07f7b69401 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -304,11 +304,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - if(mAnimation) - mAnimation->setLooping(loop); return; - } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f2a6fcb4..4c5a869856 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,32 @@ namespace MWRender { +Animation::AnimLayer::AnimLayer() + : mControllers(NULL) + , mTextKeys(NULL) + , mTime(0.0f) + , mPlaying(false) + , mLooping(false) +{ +} + + +Ogre::Real Animation::AnimationValue::getValue() const +{ + size_t idx = mIndex; + while(idx > 0 && mAnimation->mLayer[idx].mGroupName.empty()) + idx--; + if(!mAnimation->mLayer[idx].mGroupName.empty()) + return mAnimation->mLayer[idx].mTime; + return 0.0f; +} + +void Animation::AnimationValue::setValue(Ogre::Real value) +{ + mAnimation->mLayer[mIndex].mTime = value; +} + + void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mParticles.size();i++) @@ -32,7 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) , mPtr(ptr) , mController(NULL) , mInsert(NULL) @@ -41,11 +67,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentControllers(NULL) - , mCurrentKeys(NULL) - , mCurrentTime(0.0f) - , mPlaying(false) - , mLooping(false) , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) @@ -127,9 +148,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } - - if(!mCurrentControllers || (*mCurrentControllers).size() == 0) - mCurrentControllers = &objlist.mControllers; } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -215,10 +233,6 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } -void Animation::setLooping(bool loop) -{ - mLooping = loop; -} void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -301,7 +315,7 @@ Ogre::Vector3 Animation::updatePosition() Ogre::Vector3 posdiff; /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -310,7 +324,7 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -336,31 +350,31 @@ bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue< if(startkey == stopkey) return false; - mStartKey = startkey; - mLoopStartKey = mStartKey; - mStopKey = stopkey; - mNextKey = mStartKey; - ++mNextKey; + mLayer[layeridx].mStartKey = startkey; + mLayer[layeridx].mLoopStartKey = startkey; + mLayer[layeridx].mStopKey = stopkey; + mLayer[layeridx].mNextKey = startkey; + mLayer[layeridx].mNextKey++; - mCurrentTime = mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + if(layeridx == 0 && nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; return true; } -void Animation::doLoop() +void Animation::doLoop(size_t layeridx) { - mCurrentTime = mLoopStartKey->first; - mNextKey = mLoopStartKey; - ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; + mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; + mLayer[layeridx].mNextKey++; + if(layeridx == 0 && mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } -bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) +bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key) { float time = key->first; const std::string &evt = key->second; @@ -378,27 +392,27 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) return true; } - if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + if(evt.compare(0, mLayer[layeridx].mGroupName.size(), mLayer[layeridx].mGroupName) != 0 || + evt.compare(mLayer[layeridx].mGroupName.size(), 2, ": ") != 0) { - // Not ours + // Not ours, skip it return true; } - size_t off = mCurrentGroup.size()+2; + size_t off = mLayer[layeridx].mGroupName.size()+2; size_t len = evt.size() - off; if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - mLoopStartKey = key; + mLayer[layeridx].mLoopStartKey = key; return true; } if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLooping) + if(mLayer[layeridx].mLooping) { - doLoop(); - if(mCurrentTime >= time) + doLoop(layeridx); + if(mLayer[layeridx].mTime >= time) return false; return true; } @@ -412,6 +426,9 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { + // TODO: parameterize this + size_t layeridx = 0; + try { bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ @@ -422,34 +439,40 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + if(layeridx == 0) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) + for(size_t i = 0;i < iter->mControllers.size();i++) { - nonaccumctrl = dstval; - break; + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } } } if(!foundanim) { - if(!reset(keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) continue; - mCurrentKeys = &keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; - setLooping(loop); - mPlaying = true; + if(layeridx == 0) + { + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + } foundanim = true; } - if(!mNonAccumRoot) + if(!nonaccumctrl) break; mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); @@ -463,37 +486,43 @@ void Animation::play(const std::string &groupname, const std::string &start, con } } -Ogre::Vector3 Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - timepassed *= mAnimSpeedMult; - while(!mCurrentGroup.empty() && mPlaying) + duration *= mAnimSpeedMult; + for(size_t layeridx = 0;layeridx < sMaxLayers;layeridx++) { - float targetTime = mCurrentTime + timepassed; - if(mNextKey->first > targetTime) + if(mLayer[layeridx].mGroupName.empty()) + continue; + + float timepassed = duration; + while(mLayer[layeridx].mPlaying) { - mCurrentTime = targetTime; - if(mNonAccumRoot) + float targetTime = mLayer[layeridx].mTime + timepassed; + if(mLayer[layeridx].mNextKey->first > targetTime) + { + mLayer[layeridx].mTime = targetTime; + if(layeridx == 0 && mNonAccumRoot) + movement += updatePosition(); + break; + } + + NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); + mLayer[layeridx].mTime = key->first; + if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - break; + + mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + timepassed = targetTime - mLayer[layeridx].mTime; + + if(!handleTextKey(layeridx, key)) + break; } - - NifOgre::TextKeyMap::const_iterator key(mNextKey++); - mCurrentTime = key->first; - if(mNonAccumRoot) - movement += updatePosition(); - - mPlaying = (mLooping || mStopKey->first > mCurrentTime); - timepassed = targetTime - mCurrentTime; - - if(!handleTextKey(key)) - break; + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); } - for(size_t i = 0;i < (*mCurrentControllers).size();i++) - (*mCurrentControllers)[i].update(); - if(mSkelBase) { const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6393ee7c91..96138cf749 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,20 +23,15 @@ protected: { private: Animation *mAnimation; + size_t mIndex; public: - AnimationValue(Animation *anim) : mAnimation(anim) + AnimationValue(Animation *anim, size_t layeridx) + : mAnimation(anim), mIndex(layeridx) { } - virtual Ogre::Real getValue() const - { - return mAnimation->mCurrentTime; - } - - virtual void setValue(Ogre::Real value) - { - mAnimation->mCurrentTime = value; - } + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); }; Ogre::SharedPtr > mAnimationBaseValuePtr; @@ -51,21 +46,28 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::string mCurrentGroup; - std::vector > *mCurrentControllers; - const NifOgre::TextKeyMap *mCurrentKeys; - NifOgre::TextKeyMap::const_iterator mStartKey; - NifOgre::TextKeyMap::const_iterator mLoopStartKey; - NifOgre::TextKeyMap::const_iterator mStopKey; - NifOgre::TextKeyMap::const_iterator mNextKey; - float mCurrentTime; - bool mPlaying; - bool mLooping; - NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + static const size_t sMaxLayers = 1; + struct AnimLayer { + std::string mGroupName; + std::vector > *mControllers; + const NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; + NifOgre::TextKeyMap::const_iterator mNextKey; + + float mTime; + + bool mPlaying; + bool mLooping; + + AnimLayer(); + } mLayer[sMaxLayers]; + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname); @@ -85,11 +87,11 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(); + void doLoop(size_t layeridx); - bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); + bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); @@ -113,8 +115,6 @@ public: void setSpeed(float speed); - void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed);