diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98e2f91043..fbf5725c46 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -71,6 +71,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + /* As long as we remain under 128 active controllers, we can avoid + * reallocations. */ + mActiveCtrls.reserve(128); } Animation::~Animation() @@ -179,6 +182,79 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::updateActiveControllers() +{ + mActiveCtrls.clear(); + + /* First, get all controllers that don't target a node, or that target + * nodes that don't belong to any particular layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + std::vector >::const_iterator ctrl(obj->mObjectList.mControllers.begin()); + for(;ctrl != obj->mObjectList.mControllers.end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*if(getLayerByName(dstval->getNode()->getName()) >= 0)*/ + continue; + } + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + std::vector > *ctrls = NULL; + size_t layer = 0; + while(layer < sMaxLayers) + { + /* Now get controllers that target nodes that belong to this layer from + * whatever objectlist is active on this layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1<mObjectList.mControllers; + break; + } + } + + /* Check if any objectlists are active on subsequent layers. Include + * those layers if not. + */ + size_t nextlayer = layer+1; + for(;nextlayer < sMaxLayers;nextlayer++) + { + for(obj = mObjects.begin();obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1< >::const_iterator ctrl(ctrls->begin()); + for(;ctrl != ctrls->end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*ssize_t idx = getLayerByName(dstval->getNode()->getName()); + if(idx >= (ssize_t)layer && idx < (ssize_t)nextlayer)*/ + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + layer = nextlayer; + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) @@ -433,86 +509,76 @@ void Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; - try { - for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) - iter->mActiveLayers &= ~(1<::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + { + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + if(layeridx == 0) { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + } - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; - mLayer[layeridx].mPlaying = false; + if(!foundanim) + { + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + continue; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &objlist.mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; if(layeridx == 0) { - mNonAccumCtrl = NULL; + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; } - return; + iter->mActiveLayers |= (1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) - { - NifOgre::ObjectList &objlist = iter->mObjectList; - if(objlist.mTextKeys.size() == 0) - continue; + if(!nonaccumctrl) + break; - const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) - { - for(size_t i = 0;i < objlist.mControllers.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) - continue; - mLayer[layeridx].mGroupName = groupname; - mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; - mLayer[layeridx].mPlaying = true; - - if(layeridx == 0) - { - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - } - - iter->mActiveLayers |= (1< 0.0f) break; - } - if(!foundanim) - throw std::runtime_error("Failed to find animation "+groupname); - } - catch(std::exception &e) { - std::cerr<< e.what() < 0.0f) break; } + if(!foundanim) + std::cerr<< "Failed to find animation "<getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 840c22ae47..4860f44f5c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -58,6 +58,7 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; struct AnimLayer { @@ -107,6 +108,8 @@ protected: static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + void updateActiveControllers(); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation();