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:
parent
47c157303a
commit
7cce44290e
5 changed files with 91 additions and 118 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ×))
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue