From 1b1f9f7921d91bc2c2c853cfc0b0f5c71fba0574 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 18:55:28 -0700 Subject: [PATCH] Allow multiple ObjectLists to be created for Animations. addObjectList may not currently be called outside of the related constructor. --- apps/openmw/mwrender/activatoranimation.cpp | 13 ++-- apps/openmw/mwrender/animation.cpp | 80 +++++++++++++-------- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 17 +++-- apps/openmw/mwrender/npcanimation.cpp | 39 +++------- components/nifogre/ogrenifloader.cpp | 7 +- components/nifogre/ogrenifloader.hpp | 2 +- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 27ddce339..1f9a2e23c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -24,12 +24,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + const std::string name = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), name, false); + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,9 +39,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Misc); part->setRenderQueueGroup(RQG_Alpha); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30bcd3c4c..979046ea0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -36,7 +36,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) - , mAccumulate(Ogre::Vector3::ZERO) + , mAccumulate(0.0f) , mLastPosition(0.0f) , mCurrentControllers(NULL) , mCurrentKeys(NULL) @@ -62,20 +62,24 @@ Animation::~Animation() } -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) +void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly) { - assert(!mInsert); - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectLists.resize(1); - - mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectLists[0].mSkelBase) + if(!mInsert) { - mSkelBase = mObjectLists[0].mSkelBase; + mInsert = node->createChildSceneNode(); + assert(mInsert); + } + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + NifOgre::ObjectList &objlist = mObjectLists.back(); + if(objlist.mSkelBase) + { + if(!mSkelBase) + mSkelBase = objlist.mSkelBase; + + Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -87,11 +91,28 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objlist.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + if(mSkelBase != objlist.mSkelBase) + { + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!baseinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = baseinst->getBone(trgtname); + dstval->setNode(bone); + } + } + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -120,14 +141,14 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model break; } } - - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { - if(mObjectLists[0].mControllers[i].getSource().isNull()) - mObjectLists[0].mControllers[i].setSource(ctrlval); + if(objlist.mControllers[i].getSource().isNull()) + objlist.mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectLists[0].mControllers; + + if(!mCurrentControllers || (*mCurrentControllers).size() == 0) + mCurrentControllers = &objlist.mControllers; } @@ -399,9 +420,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); + Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); + mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; @@ -456,20 +478,22 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mCurrentControllers->size();i++) + + for(size_t i = 0;i < (*mCurrentControllers).size();i++) (*mCurrentControllers)[i].update(); if(mSkelBase) { - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); - for(size_t i = 0;i < mObjectLists.size();i++) + const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - Ogre::Entity *ent = mObjectLists[i].mSkelBase; + Ogre::Entity *ent = iter->mSkelBase; if(!ent) continue; - Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); - if(skelsrc != skeldst) - updateSkeletonInstance(skelsrc, skeldst); + Ogre::SkeletonInstance *inst = ent->getSkeleton(); + if(baseinst != inst) + updateSkeletonInstance(baseinst, inst); + // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. ent->getAllAnimationStates()->_notifyDirty(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3c7433db9..79262f3c5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -81,7 +81,7 @@ protected: bool handleEvent(float time, const std::string &evt); - void createObjectList(Ogre::SceneNode *node, const std::string &model); + void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7084974b8..a48b8da9f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,15 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); + addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); - createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), model, false); + + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -43,11 +43,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a713ae79e..3ef357440 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,38 +96,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); + addObjectList(node, smodel, true); if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); + addObjectList(node, "meshes\\base_anim_female.nif", true); else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + addObjectList(node, "meshes\\argonian_swimkna.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - - createObjectList(node, smodel/*skelnames*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) - { - Ogre::Entity *base = mObjectLists[0].mEntities[i]; - - base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if (mVisibilityFlags != 0) - base->setVisibilityFlags(mVisibilityFlags); - - for(unsigned int j=0; j < base->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = base->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) - { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; - - part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if(mVisibilityFlags != 0) - part->setVisibilityFlags(mVisibilityFlags); - part->setRenderQueueGroup(RQG_Alpha); - } + addObjectList(node, "meshes\\"+mNpc->mModel, true); forceUpdate(); } @@ -406,14 +381,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; - updateSkeletonInstance(skelsrc, ent->getSkeleton()); + updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); } + return ret; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 69f14b663..04cdb142f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -800,12 +800,15 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group, 0xC0000000); + + if(objectlist.mSkelBase) + parentNode->attachObject(objectlist.mSkelBase); return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fa5182aea..e3bb55064 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,7 @@ public: std::string name, const std::string &group="General"); - static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + static ObjectList createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); };