Emulate vanilla animation loops more closely

pull/43/head
Allofich 8 years ago
parent b332a13b4e
commit bf9dc45b2b

@ -1533,6 +1533,9 @@ void CharacterController::update(float duration)
updateMagicEffects();
if(mAnimQueue.size() > 1 && (mAnimation->getLoopingEnabled(mAnimQueue.front().mGroup) == true))
mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, false);
if(!cls.isActor())
{
if(mAnimQueue.size() > 1)
@ -2009,8 +2012,26 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
}
else
{
if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname && isAnimPlaying(mAnimQueue.front().mGroup))
return true;
// 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;
}
}
count = std::max(count, 1);
@ -2035,8 +2056,6 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int
}
else if(mode == 0)
{
if (!mAnimQueue.empty())
mAnimation->stopLooping(mAnimQueue.front().mGroup);
mAnimQueue.resize(1);
mAnimQueue.push_back(entry);
}

@ -1023,50 +1023,54 @@ namespace MWRender
{
float targetTime;
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0)
goto handle_loop;
targetTime = state.getTime() + timepassed;
if(textkey == textkeys.end() || textkey->first > targetTime)
{
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
updatePosition(state.getTime(), targetTime, movement);
state.setTime(std::min(targetTime, state.mStopTime));
}
else
if (state.getTime() < state.mLoopStopTime || state.mLoopCount == 0)
{
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
updatePosition(state.getTime(), textkey->first, movement);
state.setTime(textkey->first);
}
state.mPlaying = (state.getTime() < state.mStopTime);
timepassed = targetTime - state.getTime();
while(textkey != textkeys.end() && textkey->first <= state.getTime())
{
handleTextKey(state, stateiter->first, textkey, textkeys);
++textkey;
}
targetTime = state.getTime() + timepassed;
if(textkey == textkeys.end() || textkey->first > targetTime)
{
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
updatePosition(state.getTime(), targetTime, movement);
state.setTime(std::min(targetTime, state.mStopTime));
}
else
{
if(mAccumCtrl && state.mTime == mAnimationTimePtr[0]->getTimePtr())
updatePosition(state.getTime(), textkey->first, movement);
state.setTime(textkey->first);
}
if(state.getTime() >= state.mLoopStopTime && state.mLoopCount > 0)
{
handle_loop:
state.mLoopCount--;
state.setTime(state.mLoopStartTime);
state.mPlaying = true;
state.mPlaying = (state.getTime() < state.mStopTime);
timepassed = targetTime - state.getTime();
textkey = textkeys.lower_bound(state.getTime());
while(textkey != textkeys.end() && textkey->first <= state.getTime())
{
handleTextKey(state, stateiter->first, textkey, textkeys);
++textkey;
}
if(state.getTime() >= state.mLoopStopTime)
break;
}
if(state.getTime() >= state.mLoopStopTime)
{
if (!state.mLoopingEnabled)
state.mLoopCount = 0;
else if (state.mLoopCount > 0)
{
state.mLoopCount--;
state.setTime(state.mLoopStartTime);
state.mPlaying = true;
textkey = textkeys.lower_bound(state.getTime());
while(textkey != textkeys.end() && textkey->first <= state.getTime())
{
handleTextKey(state, stateiter->first, textkey, textkeys);
++textkey;
}
if(state.getTime() >= state.mLoopStopTime)
break;
}
}
if(timepassed <= 0.0f)
break;
}
@ -1095,6 +1099,21 @@ namespace MWRender
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)
{
osg::ref_ptr<osg::StateSet> previousStateset;

@ -183,6 +183,7 @@ protected:
float mSpeedMult;
bool mPlaying;
bool mLoopingEnabled;
size_t mLoopCount;
AnimPriority mPriority;
@ -190,8 +191,8 @@ protected:
bool mAutoDisable;
AnimState() : mStartTime(0.0f), mLoopStartTime(0.0f), mLoopStopTime(0.0f), mStopTime(0.0f),
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0),
mPriority(0), mBlendMask(0), mAutoDisable(true)
mTime(new float), mSpeedMult(1.0f), mPlaying(false), mLoopingEnabled(true),
mLoopCount(0), mPriority(0), mBlendMask(0), mAutoDisable(true)
{
}
~AnimState();
@ -432,6 +433,10 @@ public:
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.
void updateEffects(float duration);

Loading…
Cancel
Save