1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 08:23:51 +00:00

Handle the animation queue in mwmechanics

This commit is contained in:
Chris Robinson 2013-01-17 13:18:40 -08:00
parent 47c157303a
commit 7cce44290e
5 changed files with 91 additions and 118 deletions

View file

@ -45,18 +45,19 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
{ {
case CharState_Idle: case CharState_Idle:
mCurrentGroup = "idle"; mCurrentGroup = "idle";
mAnimation->playGroup(mCurrentGroup, 1, 1); mAnimation->play(mCurrentGroup, "start");
break; break;
case CharState_Dead: case CharState_Dead:
mCurrentGroup = "death1"; mCurrentGroup = "death1";
mAnimation->playGroup(mCurrentGroup, 1, 1); mAnimation->play(mCurrentGroup, "stop");
break; break;
} }
} }
CharacterController::CharacterController(const CharacterController &rhs) CharacterController::CharacterController(const CharacterController &rhs)
: mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames)
, mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup)
, mState(rhs.mState), mSkipAnim(rhs.mSkipAnim)
{ {
if(mAnimNames.size() == 0) if(mAnimNames.size() == 0)
return; return;
@ -79,12 +80,33 @@ void CharacterController::markerEvent(const std::string &evt)
// to this actor type // to this actor type
return; return;
} }
if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || std::string::size_type ms = mCurrentGroup.length()+2;
evt.compare(mCurrentGroup.length(), 2, ": ") != 0) if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0)
{ {
std::cerr<< "Event \""<<evt<<"\" does not belong to group \""<<mCurrentGroup<<"\"" <<std::endl; std::cerr<< "Event \""<<evt<<"\" does not belong to group \""<<mCurrentGroup<<"\"" <<std::endl;
return; return;
} }
if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1])
{
if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0)
{
mAnimQueue.pop_front();
mAnimation->play(mCurrentGroup, "loop start");
}
}
else if(mAnimQueue.size() > 0)
{
if(evt.compare(ms, evt.length()-ms, "stop") == 0)
{
mAnimQueue.pop_front();
if(mAnimQueue.size() > 0)
{
mCurrentGroup = mAnimQueue.front();
mAnimation->play(mCurrentGroup, "start");
}
}
}
} }
@ -101,7 +123,23 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
{ {
// set mState = CharState_Idle? // set mState = CharState_Idle?
if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end())
mAnimation->playGroup(groupname, mode, count); {
count = std::max(count, 1);
if(mode != 0 || mAnimQueue.size() == 0)
{
mAnimQueue.clear();
while(count-- > 0)
mAnimQueue.push_back(groupname);
mCurrentGroup = groupname;
mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"));
}
else if(mode == 0)
{
mAnimQueue.resize(1);
while(count-- > 0)
mAnimQueue.push_back(groupname);
}
}
} }
void CharacterController::skipAnim() void CharacterController::skipAnim()
@ -116,15 +154,16 @@ void CharacterController::setState(CharacterState state)
if(mAnimNames.size() == 0) if(mAnimNames.size() == 0)
return; return;
mAnimQueue.clear();
switch(mState) switch(mState)
{ {
case CharState_Idle: case CharState_Idle:
mCurrentGroup = "idle"; mCurrentGroup = "idle";
mAnimation->playGroup(mCurrentGroup, 1, 1); mAnimation->play(mCurrentGroup, "start");
break; break;
case CharState_Dead: case CharState_Dead:
mCurrentGroup = "death1"; mCurrentGroup = "death1";
mAnimation->playGroup(mCurrentGroup, 1, 1); mAnimation->play(mCurrentGroup, "start");
break; break;
} }
} }

View file

@ -23,6 +23,9 @@ class CharacterController
std::vector<std::string> mAnimNames; std::vector<std::string> mAnimNames;
typedef std::deque<std::string> AnimationQueue;
AnimationQueue mAnimQueue;
std::string mCurrentGroup; std::string mCurrentGroup;
CharacterState mState; CharacterState mState;
bool mSkipAnim; bool mSkipAnim;

View file

@ -23,6 +23,8 @@ Animation::Animation(const MWWorld::Ptr &ptr)
, mNonAccumRoot(NULL) , mNonAccumRoot(NULL)
, mStartPosition(0.0f) , mStartPosition(0.0f)
, mLastPosition(0.0f) , mLastPosition(0.0f)
, mCurrentKeys(NULL)
, mAnimState(NULL)
, mTime(0.0f) , mTime(0.0f)
{ {
} }
@ -121,14 +123,14 @@ void Animation::updatePosition(float time)
{ {
if(time == mTime) if(time == mTime)
return; return;
mCurGroup.mAnimState->setTimePosition(time); mAnimState->setTimePosition(time);
mTime = time; mTime = time;
if(mNonAccumRoot) if(mNonAccumRoot)
{ {
/* Update the animation and get the non-accumulation root's difference from the /* Update the animation and get the non-accumulation root's difference from the
* last update. */ * last update. */
mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent());
Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition;
/* Translate the accumulation root back to compensate for the move. */ /* Translate the accumulation root back to compensate for the move. */
@ -149,136 +151,81 @@ void Animation::updatePosition(float time)
void Animation::resetPosition(float time) void Animation::resetPosition(float time)
{ {
mCurGroup.mAnimState->setTimePosition(time); mAnimState->setTimePosition(time);
mTime = time; mTime = time;
mCurGroup.mNext = mCurGroup.mStart; mNextKey = mCurrentKeys->begin();
while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) while(mNextKey != mCurrentKeys->end() && mNextKey->first < time)
mCurGroup.mNext++; mNextKey++;
if(mNonAccumRoot) if(mNonAccumRoot)
{ {
mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent());
mLastPosition = mNonAccumRoot->getPosition(); mLastPosition = mNonAccumRoot->getPosition();
mAccumRoot->setPosition(mStartPosition - mLastPosition); mAccumRoot->setPosition(mStartPosition - mLastPosition);
} }
} }
bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) float Animation::findStart(const std::string &groupname, const std::string &start)
{ {
times->mTextKeys = &mTextKeys[groupname]; mNextKey = mCurrentKeys->end();
const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; if(mCurrentKeys->size() == 0)
if(textkeys.size() == 0) return 0.0f;
return false;
if(groupname == "all") if(groupname == "all")
{ {
times->mStart = times->mLoopStart = textkeys.begin(); mNextKey = mCurrentKeys->begin();
times->mLoopStop = times->mStop = textkeys.end(); return 0.0f;
times->mLoopStop--; times->mStop--;
return true;
} }
const std::string start = groupname+": start"; std::string startmarker = groupname+": "+start;
const std::string startloop = groupname+": loop start";
const std::string stop = groupname+": stop";
const std::string stoploop = groupname+": loop stop";
times->mStart = times->mLoopStart =
times->mStop = times->mLoopStop = textkeys.end();
NifOgre::TextKeyMap::const_iterator iter; NifOgre::TextKeyMap::const_iterator iter;
for(iter = textkeys.begin();iter != textkeys.end();iter++) for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++)
{ {
if(start == iter->second) if(iter->second == startmarker)
{ return iter->first;
times->mStart = iter;
times->mLoopStart = iter;
} }
else if(startloop == iter->second) return 0.0f;
times->mLoopStart = iter;
else if(stoploop == iter->second)
times->mLoopStop = iter;
else if(stop == iter->second)
{
times->mStop = iter;
if(times->mLoopStop == textkeys.end())
times->mLoopStop = iter;
return (times->mStart != textkeys.end());
}
}
return false;
} }
void Animation::playGroup(std::string groupname, int mode, int loops) void Animation::play(const std::string &groupname, const std::string &start)
{ {
GroupTimes times; float time = 0.0f;
try { try {
if(!mEntityList.mSkelBase) if(!mEntityList.mSkelBase)
throw std::runtime_error("Attempting to animate an inanimate object"); throw std::runtime_error("Attempting to animate an inanimate object");
std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); if(mAnimState)
times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(false);
times.mLoops = loops; mAnimState = mEntityList.mSkelBase->getAnimationState(groupname);
mCurrentKeys = &mTextKeys[groupname];
mAnimState->setEnabled(true);
if(!findGroupTimes(groupname, &times)) time = findStart(groupname, start);
throw std::runtime_error("Failed to find animation group "+groupname);
} }
catch(std::exception &e) { catch(std::exception &e) {
std::cerr<< e.what() <<std::endl; std::cerr<< e.what() <<std::endl;
return;
} }
times.mNext = ((mode==2) ? times.mLoopStart : times.mStart);
if(mode == 0 && mCurGroup.mAnimState) resetPosition(time);
mNextGroup = times;
else
{
if(mCurGroup.mAnimState)
mCurGroup.mAnimState->setEnabled(false);
mCurGroup = times;
mNextGroup = GroupTimes();
mCurGroup.mAnimState->setEnabled(true);
resetPosition(mCurGroup.mNext->first);
}
} }
void Animation::runAnimation(float timepassed) void Animation::runAnimation(float timepassed)
{ {
while(mCurGroup.mAnimState && timepassed > 0.0f) while(mAnimState && timepassed > 0.0f)
{ {
float targetTime = mTime + timepassed; float targetTime = mTime + timepassed;
if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime)
mCurGroup.mNext->first <= targetTime)
{ {
updatePosition(mCurGroup.mNext->first); const std::string &evt = mNextKey->second;
updatePosition(mNextKey->first);
mNextKey++;
timepassed = targetTime - mTime; timepassed = targetTime - mTime;
if(mController) if(mController)
mController->markerEvent(mCurGroup.mNext->second); mController->markerEvent(evt);
if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1)
{
mCurGroup.mLoops--;
resetPosition(mCurGroup.mLoopStart->first);
continue;
}
else if(mCurGroup.mNext == mCurGroup.mStop)
{
if(!mNextGroup.mAnimState)
break;
mCurGroup.mAnimState->setEnabled(false);
mCurGroup = mNextGroup;
mNextGroup = GroupTimes();
mCurGroup.mAnimState->setEnabled(true);
resetPosition(mCurGroup.mStart->first);
continue;
}
mCurGroup.mNext++;
continue; continue;
} }

View file

@ -15,23 +15,6 @@ namespace MWRender
class Animation class Animation
{ {
struct GroupTimes {
NifOgre::TextKeyMap *mTextKeys;
NifOgre::TextKeyMap::const_iterator mStart;
NifOgre::TextKeyMap::const_iterator mStop;
NifOgre::TextKeyMap::const_iterator mLoopStart;
NifOgre::TextKeyMap::const_iterator mLoopStop;
NifOgre::TextKeyMap::const_iterator mNext;
Ogre::AnimationState *mAnimState;
size_t mLoops;
GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0)
{ }
};
protected: protected:
MWWorld::Ptr mPtr; MWWorld::Ptr mPtr;
MWMechanics::CharacterController *mController; MWMechanics::CharacterController *mController;
@ -44,9 +27,10 @@ protected:
Ogre::Vector3 mStartPosition; Ogre::Vector3 mStartPosition;
Ogre::Vector3 mLastPosition; Ogre::Vector3 mLastPosition;
NifOgre::TextKeyMap *mCurrentKeys;
NifOgre::TextKeyMap::const_iterator mNextKey;
Ogre::AnimationState *mAnimState;
float mTime; float mTime;
GroupTimes mCurGroup;
GroupTimes mNextGroup;
/* Updates the animation to the specified time, and moves the mPtr object /* Updates the animation to the specified time, and moves the mPtr object
* based on the change since the last update or reset. */ * based on the change since the last update or reset. */
@ -55,7 +39,7 @@ protected:
* object. */ * object. */
void resetPosition(float time); void resetPosition(float time);
bool findGroupTimes(const std::string &groupname, GroupTimes *times); float findStart(const std::string &groupname, const std::string &start);
void createEntityList(Ogre::SceneNode *node, const std::string &model); void createEntityList(Ogre::SceneNode *node, const std::string &model);
@ -66,7 +50,7 @@ public:
void setController(MWMechanics::CharacterController *controller); void setController(MWMechanics::CharacterController *controller);
std::vector<std::string> getAnimationNames(); std::vector<std::string> getAnimationNames();
void playGroup(std::string groupname, int mode, int loops); void play(const std::string &groupname, const std::string &start);
virtual void runAnimation(float timepassed); virtual void runAnimation(float timepassed);
}; };

View file

@ -144,7 +144,7 @@ namespace MWRender
{ {
mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview);
mAnimation->playGroup ("inventoryhandtohand", 0, 1); mAnimation->play("inventoryhandtohand", "start");
} }
// -------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------