1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 21:53: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:
mCurrentGroup = "idle";
mAnimation->playGroup(mCurrentGroup, 1, 1);
mAnimation->play(mCurrentGroup, "start");
break;
case CharState_Dead:
mCurrentGroup = "death1";
mAnimation->playGroup(mCurrentGroup, 1, 1);
mAnimation->play(mCurrentGroup, "stop");
break;
}
}
CharacterController::CharacterController(const CharacterController &rhs)
: 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)
return;
@ -79,12 +80,33 @@ void CharacterController::markerEvent(const std::string &evt)
// to this actor type
return;
}
if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 ||
evt.compare(mCurrentGroup.length(), 2, ": ") != 0)
std::string::size_type ms = mCurrentGroup.length()+2;
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;
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?
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()
@ -116,15 +154,16 @@ void CharacterController::setState(CharacterState state)
if(mAnimNames.size() == 0)
return;
mAnimQueue.clear();
switch(mState)
{
case CharState_Idle:
mCurrentGroup = "idle";
mAnimation->playGroup(mCurrentGroup, 1, 1);
mAnimation->play(mCurrentGroup, "start");
break;
case CharState_Dead:
mCurrentGroup = "death1";
mAnimation->playGroup(mCurrentGroup, 1, 1);
mAnimation->play(mCurrentGroup, "start");
break;
}
}

View file

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

View file

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

View file

@ -15,23 +15,6 @@ namespace MWRender
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:
MWWorld::Ptr mPtr;
MWMechanics::CharacterController *mController;
@ -44,9 +27,10 @@ protected:
Ogre::Vector3 mStartPosition;
Ogre::Vector3 mLastPosition;
NifOgre::TextKeyMap *mCurrentKeys;
NifOgre::TextKeyMap::const_iterator mNextKey;
Ogre::AnimationState *mAnimState;
float mTime;
GroupTimes mCurGroup;
GroupTimes mNextGroup;
/* Updates the animation to the specified time, and moves the mPtr object
* based on the change since the last update or reset. */
@ -55,7 +39,7 @@ protected:
* object. */
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);
@ -66,7 +50,7 @@ public:
void setController(MWMechanics::CharacterController *controller);
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);
};

View file

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