1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 23:53:52 +00:00

Emulate vanilla animation loops more closely

This commit is contained in:
Allofich 2016-08-18 01:08:54 +09:00
parent b332a13b4e
commit bf9dc45b2b
3 changed files with 83 additions and 40 deletions

View file

@ -1533,6 +1533,9 @@ void CharacterController::update(float duration)
updateMagicEffects(); updateMagicEffects();
if(mAnimQueue.size() > 1 && (mAnimation->getLoopingEnabled(mAnimQueue.front().mGroup) == true))
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, false);
if(!cls.isActor()) if(!cls.isActor())
{ {
if(mAnimQueue.size() > 1) if(mAnimQueue.size() > 1)
@ -2009,8 +2012,26 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
} }
else else
{ {
if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname && isAnimPlaying(mAnimQueue.front().mGroup)) // If the given animation is a looped animation, is already playing
// and has not yet reached its Loop Stop key, make it the only animation
// in the queue, and retain the loop count from the animation that was
// already playing. This emulates observed behavior from the original
// engine and allows banners to animate correctly.
if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname &&
mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop start") >= 0)
{
float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop");
if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key
endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop");
if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop))
{
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, true);
mAnimQueue.resize(1);
return true; return true;
}
}
count = std::max(count, 1); count = std::max(count, 1);
@ -2035,8 +2056,6 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
} }
else if(mode == 0) else if(mode == 0)
{ {
if (!mAnimQueue.empty())
mAnimation->stopLooping(mAnimQueue.front().mGroup);
mAnimQueue.resize(1); mAnimQueue.resize(1);
mAnimQueue.push_back(entry); mAnimQueue.push_back(entry);
} }

View file

@ -1023,9 +1023,8 @@ namespace MWRender
{ {
float targetTime; float targetTime;
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) if (state.getTime() < state.mLoopStopTime || state.mLoopCount == 0)
goto handle_loop; {
targetTime = state.getTime() + timepassed; targetTime = state.getTime() + timepassed;
if(textkey == textkeys.end() || textkey->first > targetTime) if(textkey == textkeys.end() || textkey->first > targetTime)
{ {
@ -1048,10 +1047,14 @@ namespace MWRender
handleTextKey(state, stateiter->first, textkey, textkeys); handleTextKey(state, stateiter->first, textkey, textkeys);
++textkey; ++textkey;
} }
}
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0) if(state.getTime() >= state.mLoopStopTime)
{
if (!state.mLoopingEnabled)
state.mLoopCount = 0;
else if (state.mLoopCount > 0)
{ {
handle_loop:
state.mLoopCount--; state.mLoopCount--;
state.setTime(state.mLoopStartTime); state.setTime(state.mLoopStartTime);
state.mPlaying = true; state.mPlaying = true;
@ -1066,6 +1069,7 @@ namespace MWRender
if(state.getTime() >= state.mLoopStopTime) if(state.getTime() >= state.mLoopStopTime)
break; break;
} }
}
if(timepassed <= 0.0f) if(timepassed <= 0.0f)
break; break;
@ -1095,6 +1099,21 @@ namespace MWRender
return movement; return movement;
} }
void Animation::setLoopingEnabled(const std::string &groupname, bool enabled)
{
AnimStateMap::iterator state(mStates.find(groupname));
if(state != mStates.end())
state->second.mLoopingEnabled = enabled;
}
bool Animation::getLoopingEnabled(const std::string &groupname) const
{
AnimStateMap::const_iterator state(mStates.find(groupname));
if(state != mStates.end())
return state->second.mLoopingEnabled;
return false;
}
void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature)
{ {
osg::ref_ptr<osg::StateSet> previousStateset; osg::ref_ptr<osg::StateSet> previousStateset;

View file

@ -183,6 +183,7 @@ protected:
float mSpeedMult; float mSpeedMult;
bool mPlaying; bool mPlaying;
bool mLoopingEnabled;
size_t mLoopCount; size_t mLoopCount;
AnimPriority mPriority; AnimPriority mPriority;
@ -190,8 +191,8 @@ protected:
bool mAutoDisable; bool mAutoDisable;
AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f), AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0), mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopingEnabled(true),
mPriority(0), mBlendMask(0), mAutoDisable(true) mLoopCount(0), mPriority(0), mBlendMask(0), mAutoDisable(true)
{ {
} }
~AnimState(); ~AnimState();
@ -432,6 +433,10 @@ public:
virtual osg::Vec3f runAnimation(float duration); virtual osg::Vec3f runAnimation(float duration);
void setLoopingEnabled(const std::string &groupname, bool enabled);
bool getLoopingEnabled(const std::string &groupname) const;
/// This is typically called as part of runAnimation, but may be called manually if needed. /// This is typically called as part of runAnimation, but may be called manually if needed.
void updateEffects(float duration); void updateEffects(float duration);