Implement multiple emitter nodes for NiBSPArrayController

The particles for the flame, frost and storm atronachs work correctly now.
deque
scrawl 10 years ago
parent dd77954512
commit c2a91148f3

@ -53,6 +53,24 @@
#include "material.hpp" #include "material.hpp"
#include "mesh.hpp" #include "mesh.hpp"
#include "controller.hpp" #include "controller.hpp"
#include "particles.hpp"
namespace
{
void getAllNiNodes(const Nif::Node* node, std::vector<const Nif::NiNode*>& out)
{
const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(node);
if (ninode)
{
out.push_back(ninode);
for (unsigned int i=0; i<ninode->children.length(); ++i)
if (!ninode->children[i].empty())
getAllNiNodes(ninode->children[i].getPtr(), out);
}
}
}
namespace NifOgre namespace NifOgre
{ {
@ -902,9 +920,28 @@ class NIFObjectLoader
{ {
int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex);
Ogre::Bone *trgtbone = scene->mSkelBase->getSkeleton()->getBone(trgtid); 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. // so the emitters/affectors can access it easily.
partsys->getUserObjectBindings().setUserAny(Ogre::Any(trgtbone)); std::vector<Ogre::Bone*> bones;
if (partctrl->recType == Nif::RC_NiBSPArrayController)
{
std::vector<const Nif::NiNode*> 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; i<nodes.size(); ++i)
{
bones.push_back(scene->mSkelBase->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()); createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName());
} }

@ -16,7 +16,7 @@
class NifEmitter : public Ogre::ParticleEmitter class NifEmitter : public Ogre::ParticleEmitter
{ {
public: public:
Ogre::Bone* mEmitterBone; std::vector<Ogre::Bone*> mEmitterBones;
Ogre::Bone* mParticleBone; Ogre::Bone* mParticleBone;
Ogre::ParticleSystem* getPartSys() { return mParent; } Ogre::ParticleSystem* getPartSys() { return mParent; }
@ -131,7 +131,8 @@ public:
NifEmitter(Ogre::ParticleSystem *psys) NifEmitter(Ogre::ParticleSystem *psys)
: Ogre::ParticleEmitter(psys) : Ogre::ParticleEmitter(psys)
{ {
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny()); mEmitterBones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
assert (!mEmitterBones.empty());
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode()); Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent()); mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
initDefaults("Nif"); initDefaults("Nif");
@ -170,8 +171,10 @@ public:
Ogre::Real& timeToLive = particle->timeToLive; Ogre::Real& timeToLive = particle->timeToLive;
#endif #endif
Ogre::Node* emitterBone = mEmitterBones.at((int)(::rand()/(RAND_MAX+1.0)*mEmitterBones.size()));
position = xOff + yOff + zOff + position = xOff + yOff + zOff +
mParticleBone->_getDerivedOrientation().Inverse() * (mEmitterBone->_getDerivedPosition() mParticleBone->_getDerivedOrientation().Inverse() * (emitterBone->_getDerivedPosition()
- mParticleBone->_getDerivedPosition()); - mParticleBone->_getDerivedPosition());
// Generate complex data by reference // Generate complex data by reference
@ -181,7 +184,7 @@ public:
Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom();
Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom();
direction = (mParticleBone->_getDerivedOrientation().Inverse() direction = (mParticleBone->_getDerivedOrientation().Inverse()
* mEmitterBone->_getDerivedOrientation() * * emitterBone->_getDerivedOrientation() *
Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) *
Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) *
Ogre::Vector3::UNIT_Z; Ogre::Vector3::UNIT_Z;
@ -635,7 +638,9 @@ public:
, mPosition(0.0f) , mPosition(0.0f)
, mDirection(0.0f) , mDirection(0.0f)
{ {
mEmitterBone = Ogre::any_cast<Ogre::Bone*>(psys->getUserObjectBindings().getUserAny()); std::vector<Ogre::Bone*> bones = Ogre::any_cast<NiNodeHolder>(psys->getUserObjectBindings().getUserAny()).mBones;
assert (!bones.empty());
mEmitterBone = bones[0];
Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode()); Ogre::TagPoint* tag = static_cast<Ogre::TagPoint*>(mParent->getParentNode());
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent()); mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());

@ -38,4 +38,13 @@ class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys);
}; };
struct NiNodeHolder
{
std::vector<Ogre::Bone*> 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 */ #endif /* OENGINE_OGRE_PARTICLES_H */

Loading…
Cancel
Save