mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 21:45:32 +00:00
Implement multiple emitter nodes for NiBSPArrayController
The particles for the flame, frost and storm atronachs work correctly now.
This commit is contained in:
parent
dd77954512
commit
c2a91148f3
3 changed files with 58 additions and 7 deletions
|
@ -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<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
|
||||
{
|
||||
|
@ -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<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());
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
class NifEmitter : public Ogre::ParticleEmitter
|
||||
{
|
||||
public:
|
||||
Ogre::Bone* mEmitterBone;
|
||||
std::vector<Ogre::Bone*> 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<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());
|
||||
mParticleBone = static_cast<Ogre::Bone*>(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<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());
|
||||
mParticleBone = static_cast<Ogre::Bone*>(tag->getParent());
|
||||
|
||||
|
|
|
@ -38,4 +38,13 @@ class GravityAffectorFactory : public Ogre::ParticleAffectorFactory
|
|||
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 */
|
||||
|
|
Loading…
Reference in a new issue