From 24f1eba9025f3e7dca4ff20fcd9fb9fba57eb74a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 22:45:43 -0700 Subject: [PATCH] Keep track of whether an animation supplies movement Also handle it when it doesn't. --- apps/openmw/mwmechanics/character.cpp | 18 ++++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 22 ++++++++++++++++------ apps/openmw/mwrender/animation.hpp | 5 ++++- apps/openmw/mwrender/npcanimation.cpp | 6 +++--- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9397b2e35..0085f8de6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,7 +103,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false), mMovingAnim(false) { if(!mAnimation) return; @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -180,6 +180,9 @@ void CharacterController::update(float duration, Movement &movement) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); + // If this animation isn't moving us sideways, do it manually + if(!mMovingAnim) + movement.mPosition[0] += vec.x * (speed*duration); // Apply any forward/backward movement manually movement.mPosition[1] += vec.y * (speed*duration); } @@ -194,6 +197,9 @@ void CharacterController::update(float duration, Movement &movement) // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); + // If this animation isn't moving us forward/backward, do it manually + if(!mMovingAnim) + movement.mPosition[1] += vec.y * (speed*duration); } else if(rot.z != 0.0f && !inwater && !sneak) { @@ -211,7 +217,7 @@ void CharacterController::update(float duration, Movement &movement) mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } } @@ -244,7 +250,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); + mMovingAnim = mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -272,10 +278,10 @@ void CharacterController::setState(CharacterState state, bool loop) std::string anim; getStateInfo(mState, &anim); - if(mAnimation->hasAnimation(anim)) + if((mMovingAnim=mAnimation->hasAnimation(anim)) != false) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); + mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index ffd220ff2..8e4bd2f09 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,8 @@ class CharacterController CharacterState mState; bool mSkipAnim; + bool mMovingAnim; + public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); virtual ~CharacterController(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0f509d276..5838b1ff3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -317,7 +317,7 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname) { const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; @@ -340,8 +340,8 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum; + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum; return startpos.distance(endpos) / (stoptime-starttime); } @@ -515,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void 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, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -523,6 +523,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) iter->mActiveLayers &= ~(1<mActiveLayers |= (1< 0.0f) break; + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, mAccumulate, groupname); + if(mAnimVelocity > 1.0f) + { + movinganim = (nonaccumctrl==mNonAccumCtrl); + break; + } } if(!foundanim) std::cerr<< "Failed to find animation "< *nonaccumctrl, + const Ogre::Vector3 &accum, const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on @@ -135,8 +136,10 @@ public: * \param loops How many times to loop the animation. This will use the * "loop start" and "loop stop" markers if they exist, * otherwise it will use "start" and "stop". + * \return Boolean specifying whether the animation will return movement + * for the character at all. */ - void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + bool play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b05b4ba6..c0f2e7e29 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -97,10 +97,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); addObjectList(node, smodel, true); - if(!mNpc->isMale() && !isBeast) - addObjectList(node, "meshes\\base_anim_female.nif", true); - else if(mBodyPrefix.find("argonian") != std::string::npos) + if(mBodyPrefix.find("argonian") != std::string::npos) addObjectList(node, "meshes\\argonian_swimkna.nif", true); + else if(!mNpc->isMale() && !isBeast) + addObjectList(node, "meshes\\base_anim_female.nif", true); if(mNpc->mModel.length() > 0) addObjectList(node, "meshes\\"+mNpc->mModel, true);