From c2a91148f3997c9a02ee2947671ffb6dbf824a9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Aug 2014 21:56:32 +0200 Subject: [PATCH] Implement multiple emitter nodes for NiBSPArrayController The particles for the flame, frost and storm atronachs work correctly now. --- components/nifogre/ogrenifloader.cpp | 41 ++++++++++++++++++++++++++-- components/nifogre/particles.cpp | 15 ++++++---- components/nifogre/particles.hpp | 9 ++++++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 86d713aab..83716764c 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -53,6 +53,24 @@ #include "material.hpp" #include "mesh.hpp" #include "controller.hpp" +#include "particles.hpp" + +namespace +{ + + void getAllNiNodes(const Nif::Node* node, std::vector& out) + { + const Nif::NiNode* ninode = dynamic_cast(node); + if (ninode) + { + out.push_back(ninode); + for (unsigned int i=0; ichildren.length(); ++i) + if (!ninode->children[i].empty()) + getAllNiNodes(ninode->children[i].getPtr(), out); + } + } + +} namespace NifOgre { @@ -902,9 +920,28 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); - // Set the emitter bone as user data on the particle system + // Set the emitter bone(s) as user data on the particle system // so the emitters/affectors can access it easily. - partsys->getUserObjectBindings().setUserAny(Ogre::Any(trgtbone)); + std::vector bones; + if (partctrl->recType == Nif::RC_NiBSPArrayController) + { + std::vector nodes; + getAllNiNodes(partctrl->emitter.getPtr(), nodes); + if (nodes.empty()) + throw std::runtime_error("Emitter for NiBSPArrayController must be a NiNode"); + for (unsigned int i=0; imSkelBase->getSkeleton()->getBone( + NIFSkeletonLoader::lookupOgreBoneHandle(name, nodes[i]->recIndex))); + } + } + else + { + bones.push_back(trgtbone); + } + NiNodeHolder holder; + holder.mBones = bones; + partsys->getUserObjectBindings().setUserAny(Ogre::Any(holder)); createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName()); } diff --git a/components/nifogre/particles.cpp b/components/nifogre/particles.cpp index 47dce774f..caf82cf42 100644 --- a/components/nifogre/particles.cpp +++ b/components/nifogre/particles.cpp @@ -16,7 +16,7 @@ class NifEmitter : public Ogre::ParticleEmitter { public: - Ogre::Bone* mEmitterBone; + std::vector mEmitterBones; Ogre::Bone* mParticleBone; Ogre::ParticleSystem* getPartSys() { return mParent; } @@ -131,7 +131,8 @@ public: NifEmitter(Ogre::ParticleSystem *psys) : Ogre::ParticleEmitter(psys) { - mEmitterBone = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()); + mEmitterBones = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones; + assert (!mEmitterBones.empty()); Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); mParticleBone = static_cast(tag->getParent()); initDefaults("Nif"); @@ -170,8 +171,10 @@ public: Ogre::Real& timeToLive = particle->timeToLive; #endif + Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size())); + position = xOff + yOff + zOff + - mParticleBone->_getDerivedOrientation().Inverse() * (mEmitterBone->_getDerivedPosition() + mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition() - mParticleBone->_getDerivedPosition()); // Generate complex data by reference @@ -181,7 +184,7 @@ public: Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); direction = (mParticleBone->_getDerivedOrientation().Inverse() - * mEmitterBone->_getDerivedOrientation() * + * emitterBone->_getDerivedOrientation() * Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * Ogre::Vector3::UNIT_Z; @@ -635,7 +638,9 @@ public: , mPosition(0.0f) , mDirection(0.0f) { - mEmitterBone = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()); + std::vector bones = Ogre::any_cast(psys->getUserObjectBindings().getUserAny()).mBones; + assert (!bones.empty()); + mEmitterBone = bones[0]; Ogre::TagPoint* tag = static_cast(mParent->getParentNode()); mParticleBone = static_cast(tag->getParent()); diff --git a/components/nifogre/particles.hpp b/components/nifogre/particles.hpp index e1f3fd282..6efc669fe 100644 --- a/components/nifogre/particles.hpp +++ b/components/nifogre/particles.hpp @@ -38,4 +38,13 @@ class GravityAffectorFactory : public Ogre::ParticleAffectorFactory Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); }; +struct NiNodeHolder +{ + std::vector mBones; + + // Ogre::Any needs this for some reason + friend std::ostream& operator<<(std::ostream& o, const NiNodeHolder& r) + { return o; } +}; + #endif /* OENGINE_OGRE_PARTICLES_H */