From a932a89e02d874bc4ae4ec0df17d3d7ef24d9dc4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Jul 2013 01:30:03 -0700 Subject: [PATCH] Specify the velocity-based animation speed multiplier when playing it --- apps/openmw/mwmechanics/character.cpp | 19 +++--- apps/openmw/mwmechanics/character.hpp | 2 + apps/openmw/mwrender/animation.cpp | 93 ++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 8 +-- 4 files changed, 71 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0d62e546a1..355a8f93d3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -207,8 +207,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->disable(mCurrentMovement); mCurrentMovement = movement; if(!mCurrentMovement.empty()) + { + float vel, speed = 0.0f; + if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f) + speed = mMovementSpeed / vel; mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false, - 1.0f, "start", "stop", 0.0f, ~0ul); + speed, "start", "stop", 0.0f, ~0ul); + } } } @@ -226,6 +231,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_Idle) , mMovementState(CharState_None) + , mMovementSpeed(0.0f) , mDeathState(CharState_None) , mWeaponType(WeapType_None) , mSkipAnim(false) @@ -281,7 +287,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::update(float duration, Movement &movement) { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - float speed = 0.0f; if(!cls.isActor()) { @@ -308,7 +313,7 @@ void CharacterController::update(float duration, Movement &movement) bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); Ogre::Vector3 vec = cls.getMovementVector(mPtr); Ogre::Vector3 rot = cls.getRotationVector(mPtr); - speed = cls.getSpeed(mPtr); + mMovementSpeed = cls.getSpeed(mPtr); // advance athletics if(vec.squaredLength() > 0 && mPtr.getRefData().getHandle() == "player") @@ -355,8 +360,8 @@ void CharacterController::update(float duration, Movement &movement) //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; } - vec.x *= speed; - vec.y *= speed; + vec.x *= mMovementSpeed; + vec.y *= mMovementSpeed; CharacterState movestate = CharState_None; CharacterState idlestate = CharState_SpecialIdle; @@ -541,11 +546,9 @@ void CharacterController::update(float duration, Movement &movement) if(mAnimation && !mSkipAnim) { - mAnimation->setSpeed(speed); - Ogre::Vector3 moved = mAnimation->runAnimation(duration); // Ensure we're moving in generally the right direction - if (speed > 0.f) + if(mMovementSpeed > 0.f) { if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || (movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 84f324fad7..6dfd7e6ca6 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -105,8 +105,10 @@ class CharacterController CharacterState mIdleState; std::string mCurrentIdle; + CharacterState mMovementState; std::string mCurrentMovement; + float mMovementSpeed; CharacterState mDeathState; std::string mCurrentDeath; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0888d391b3..147e7c90ed 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -52,8 +52,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mNonAccumCtrl(NULL) , mAccumulate(0.0f) - , mAnimVelocity(0.0f) - , mAnimSpeedMult(1.0f) { for(size_t i = 0;i < sNumGroups;i++) mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this)); @@ -245,7 +243,6 @@ void Animation::clearAnimSources() mAnimationValuePtr[i]->setAnimName(std::string()); mNonAccumCtrl = NULL; - mAnimVelocity = 0.0f; mAccumRoot = NULL; mNonAccumRoot = NULL; @@ -298,13 +295,6 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) mAccumulate = accum; } -void Animation::setSpeed(float speed) -{ - mAnimSpeedMult = 1.0f; - if(speed > 0.0f && mAnimVelocity > 1.0f) - mAnimSpeedMult = speed / mAnimVelocity; -} - void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -344,6 +334,61 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node return 0.0f; } +float Animation::getVelocity(const std::string &groupname) const +{ + /* Look in reverse; last-inserted source has priority. */ + AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); + for(;animsrc != mAnimSources.rend();animsrc++) + { + const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; + if(findGroupStart(keys, groupname) != keys.end()) + break; + } + if(animsrc == mAnimSources.rend()) + return 0.0f; + + float velocity = 0.0f; + const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys; + const std::vector >&ctrls = (*animsrc)->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) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + + // If there's no velocity, keep looking + if(!(velocity > 1.0f)) + { + AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); + while(*animiter != *animsrc) + ++animiter; + + while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) + { + const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; + const std::vector >&ctrls = (*animiter)->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) + { + velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname); + break; + } + } + } + } + + return velocity; +} + + static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) { if(skelsrc->hasBone(bone->getName())) @@ -599,9 +644,7 @@ void Animation::resetActiveGroups() mAnimationValuePtr[grp]->setAnimName((active == mStates.end()) ? std::string() : active->first); } - mNonAccumCtrl = NULL; - mAnimVelocity = 0.0f; if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f)) return; @@ -619,35 +662,10 @@ void Animation::resetActiveGroups() dstval = static_cast*>(ctrls[i].getDestination().getPointer()); if(dstval->getNode() == mNonAccumRoot) { - mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first); mNonAccumCtrl = dstval; break; } } - - // If there's no velocity, keep looking - if(!(mAnimVelocity > 1.0f)) - { - AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin(); - while(*animiter != animsrc) - ++animiter; - - while(!(mAnimVelocity > 1.0f) && ++animiter != mAnimSources.rend()) - { - const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys; - const std::vector >&ctrls = (*animiter)->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); - break; - } - } - } - } } @@ -685,7 +703,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - duration *= mAnimSpeedMult; AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4955acb3bd..bc7fd3d22f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -101,9 +101,6 @@ protected: ObjectAttachMap mAttachedObjects; - float mAnimVelocity; - float mAnimSpeedMult; - /* Sets the appropriate animations on the bone groups based on priority. */ void resetActiveGroups(); @@ -174,8 +171,6 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); - void setSpeed(float speed); - /** Plays an animation. * \param groupname Name of the animation group to play. * \param priority Priority of the animation. The animation will play on @@ -215,6 +210,9 @@ public: */ void disable(const std::string &groupname); + /** Retrieves the velocity (in units per second) that the animation will move. */ + float getVelocity(const std::string &groupname) const; + virtual Ogre::Vector3 runAnimation(float duration); virtual void showWeapons(bool showWeapon);