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:
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:
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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, ×))
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue