diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a334db8349..518c34f629 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -171,7 +171,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim std::string group; getCurrentGroup(group); - mMovingAnim = mAnimation->play(group, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -346,6 +346,7 @@ void CharacterController::update(float duration, Movement &movement) else { mMovingAnim = mAnimation->play(mAnimQueue.front().first, + MWRender::Animation::Priority_Default, "start", "stop", 0.0f, mAnimQueue.front().second); mAnimQueue.pop_front(); @@ -381,7 +382,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCharState = CharState_SpecialIdle; mLooping = false; - mMovingAnim = mAnimation->play(groupname, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); + mMovingAnim = mAnimation->play(groupname, MWRender::Animation::Priority_Default, + ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -424,7 +426,8 @@ void CharacterController::forceStateUpdate() std::string group; getCurrentGroup(group); - mMovingAnim = mAnimation->play(group, "start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default, + "start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0); mAnimation->showWeapons(mWeapState != WeapState_None && mWeapState != WeapState_HandToHand && mWeapState != WeapState_Spell); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7f48d83243..39065fefad 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -372,7 +372,7 @@ void Animation::updatePosition(float time, Ogre::Vector3 &position) mAccumRoot->setPosition(-mLastPosition); } -bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) +bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -413,9 +413,6 @@ bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, NifOgre state.mNextKey++; } - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(state.mTime) * mAccumulate; - return true; } @@ -429,8 +426,6 @@ bool Animation::doLoop(AnimState &state) state.mNextKey = state.mLoopStartKey; state.mNextKey++; state.mPlaying = true; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(state.mTime) * mAccumulate; return true; } @@ -476,6 +471,11 @@ bool Animation::handleTextKey(AnimState &state, const std::string &groupname, co if(state.mTime >= time) return false; } + + // Ugly + if(mNonAccumCtrl && groupname == mAnimationValuePtr[0]->getAnimName()) + mLastPosition = mNonAccumCtrl->getTranslation(state.mTime) * mAccumulate; + return true; } @@ -484,78 +484,101 @@ bool Animation::handleTextKey(AnimState &state, const std::string &groupname, co } -bool Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) +bool Animation::play(const std::string &groupname, Priority priority, const std::string &start, const std::string &stop, float startpoint, size_t loops) { - if(!mSkelBase || groupname.empty()) + if(!mSkelBase) return false; + if(groupname.empty()) + return resetActiveGroups(); + AnimStateMap::iterator stateiter = mStates.find(groupname); if(stateiter != mStates.end()) - mStates.erase(stateiter); + { + stateiter->second.mPriority = priority; + return resetActiveGroups(); + } // HACK: Don't clear all active animations mStates.clear(); - bool movinganim = false; - bool foundanim = false; - /* Look in reverse; last-inserted source has priority. */ AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); for(;iter != mAnimSources.rend();iter++) { - const NifOgre::TextKeyMap &keys = iter->mTextKeys; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(mNonAccumRoot) + AnimState state; + if(reset(state, iter->mTextKeys, groupname, start, stop, startpoint)) { - for(size_t i = 0;i < iter->mControllers[0].size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[0][i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - AnimState state; - if(!reset(state, keys, nonaccumctrl, groupname, start, stop, startpoint)) - continue; - foundanim = true; - state.mSource = &*iter; state.mLoopCount = loops; state.mPlaying = true; + state.mPriority = priority; mStates[groupname] = state; - // FIXME - mAnimationValuePtr[0]->setAnimName(groupname); - - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - - if(mAccumulate == Ogre::Vector3(0.0f)) - break; - } - - if(!nonaccumctrl) - break; - - mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, mAccumulate, groupname); - if(mAnimVelocity > 1.0f) - { - movinganim = (nonaccumctrl==mNonAccumCtrl); break; } } - if(!foundanim) + if(iter == mAnimSources.rend()) std::cerr<< "Failed to find animation "<second.mGroups&(1<second.mPriority < state->second.mPriority) + active = state; + } + + mAnimationValuePtr[grp]->setAnimName((active == mStates.end()) ? + std::string() : active->first); + } + + mNonAccumCtrl = NULL; + mAnimVelocity = 0.0f; + mLastPosition = Ogre::Vector3(0.0f); + + if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) + return false; + + AnimStateMap::const_iterator state = mStates.find(mAnimationValuePtr[0]->getAnimName()); + if(state == mStates.end()) + return false; + + bool ismoving = false; + + const NifOgre::TextKeyMap &keys = state->second.mSource->mTextKeys; + std::vector >&ctrls = state->second.mSource->mControllers[0]; + for(size_t i = 0;i < ctrls.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = static_cast*>(ctrls[i].getDestination().getPointer()); + if(dstval->getNode() == mNonAccumRoot) + { + mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first); + ismoving = (mAnimVelocity > 1.0f); + + mLastPosition = dstval->getTranslation(state->second.mTime) * mAccumulate; + + mNonAccumCtrl = dstval; + break; + } + } + + return ismoving; +} + + bool Animation::getInfo(const std::string &groupname, float *complete, std::string *start, std::string *stop) const { AnimStateMap::const_iterator iter = mStates.find(groupname); @@ -591,14 +614,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(state.mNextKey->first > targetTime) { state.mTime = targetTime; - if(mNonAccumCtrl) + if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName()) updatePosition(state.mTime, movement); break; } NifOgre::TextKeyMap::const_iterator key(state.mNextKey++); state.mTime = key->first; - if(mNonAccumCtrl) + if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName()) updatePosition(state.mTime, movement); state.mPlaying = (key != state.mStopKey); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 15c242d227..d6dac80880 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -14,6 +14,14 @@ namespace MWRender class Animation { +public: + enum Priority { + Priority_Nil = -1, /* Do not use */ + Priority_Default, + + Num_Priorities + }; + protected: static const size_t sNumGroups = 1; @@ -55,6 +63,8 @@ protected: bool mPlaying; size_t mLoopCount; + int mPriority; + AnimState() : mSource(NULL), mTime(0.0f), mPlaying(false), mLoopCount(0) { } }; @@ -79,6 +89,11 @@ protected: Ogre::SharedPtr mAnimationValuePtr[sNumGroups]; + /* Sets the appropriate animations on the bone groups based on priority. + * Returns true if the NonAccum root will provide movement. + */ + bool resetActiveGroups(); + static size_t detectAnimGroup(const Ogre::Node *node); static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, @@ -102,7 +117,6 @@ protected: * false. */ bool reset(AnimState &state, const NifOgre::TextKeyMap &keys, - NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint); @@ -136,6 +150,9 @@ public: /** Plays an animation. * \param groupname Name of the animation group to play. + * \param priority Priority of the animation. The animation will play on + * bone groups that don't have another animation set of a + * higher priority. * \param start Key marker from which to start. * \param stop Key marker to stop at. * \param startpoint How far in between the two markers to start. 0 starts @@ -146,7 +163,7 @@ public: * \return Boolean specifying whether the animation will return movement * for the character at all. */ - bool play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + bool play(const std::string &groupname, Priority priority, const std::string &start, const std::string &stop, float startpoint, size_t loops); void disable(const std::string &groupname); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 4d9680b2c1..fb95f75f51 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -172,7 +172,7 @@ namespace MWRender if(groupname != mCurrentAnimGroup) { mCurrentAnimGroup = groupname; - mAnimation->play(mCurrentAnimGroup, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentAnimGroup, Animation::Priority_Default, "start", "stop", 0.0f, 0); } mAnimation->forceUpdate(); @@ -199,7 +199,7 @@ namespace MWRender mAnimation->showWeapons(true); mCurrentAnimGroup = "inventoryhandtohand"; - mAnimation->play(mCurrentAnimGroup, "start", "stop", 0.0f, 0); + mAnimation->play(mCurrentAnimGroup, Animation::Priority_Default, "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- @@ -233,7 +233,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", 0.0f, 0); + mAnimation->play("idle", Animation::Priority_Default, "start", "stop", 0.0f, 0); updateCamera(); }