From 7191f6ed2a7f500b1d51275d8ece011ed9590f8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 14:36:24 -0700 Subject: [PATCH] Start a Nif-style particle emitter Not complete yet (doesn't handle the vertical or horizontal direction/angle), and should probably be renamed. --- components/nifogre/ogrenifloader.cpp | 5 +- libs/openengine/ogre/particles.cpp | 217 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 13 ++ libs/openengine/ogre/renderer.cpp | 12 ++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 248 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4e6d3b3c45..d546ca2712 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -351,7 +351,7 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, @@ -359,6 +359,9 @@ class NIFObjectLoader emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 61ebddc562..a6bc78d5fb 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -2,9 +2,226 @@ #include #include +#include #include #include +/* FIXME: "Nif" isn't really an appropriate emitter name. */ +class NifEmitter : public Ogre::ParticleEmitter +{ +public: + /** Command object for the emitter width (see Ogre::ParamCommand).*/ + class CmdWidth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getWidth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter height (see Ogre::ParamCommand).*/ + class CmdHeight : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getHeight()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter depth (see Ogre::ParamCommand).*/ + class CmdDepth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getDepth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); + } + }; + + + NifEmitter(Ogre::ParticleSystem *psys) + : Ogre::ParticleEmitter(psys) + { + initDefaults("Nif"); + } + + /** See Ogre::ParticleEmitter. */ + unsigned short _getEmissionCount(Ogre::Real timeElapsed) + { + // Use basic constant emission + return genConstantEmissionCount(timeElapsed); + } + + /** See Ogre::ParticleEmitter. */ + void _initParticle(Ogre::Particle *particle) + { + Ogre::Vector3 xOff, yOff, zOff; + + // Call superclass + ParticleEmitter::_initParticle(particle); + + xOff = Ogre::Math::SymmetricRandom() * mXRange; + yOff = Ogre::Math::SymmetricRandom() * mYRange; + zOff = Ogre::Math::SymmetricRandom() * mZRange; + + particle->position = mPosition + xOff + yOff + zOff; + + // Generate complex data by reference + genEmissionColour(particle->colour); + genEmissionDirection(particle->direction); + genEmissionVelocity(particle->direction); + + // Generate simpler data + particle->timeToLive = particle->totalTimeToLive = genEmissionTTL(); + } + + /** Overloaded to update the trans. matrix */ + void setDirection(const Ogre::Vector3 &dir) + { + ParticleEmitter::setDirection(dir); + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param + size Vector describing the size of the area. The area extends + around the center point by half the x, y and z components of + this vector. The box is aligned such that it's local Z axis points + along it's direction (see setDirection) + */ + void setSize(const Ogre::Vector3 &size) + { + mSize = size; + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param x,y,z + Individual axis lengths describing the size of the area. The area + extends around the center point by half the x, y and z components + of this vector. The box is aligned such that it's local Z axis + points along it's direction (see setDirection) + */ + void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) + { + mSize.x = x; + mSize.y = y; + mSize.z = z; + genAreaAxes(); + } + + /** Sets the width (local x size) of the emitter. */ + void setWidth(Ogre::Real width) + { + mSize.x = width; + genAreaAxes(); + } + /** Gets the width (local x size) of the emitter. */ + Ogre::Real getWidth(void) const + { return mSize.x; } + /** Sets the height (local y size) of the emitter. */ + void setHeight(Ogre::Real height) + { + mSize.y = height; + genAreaAxes(); + } + /** Gets the height (local y size) of the emitter. */ + Ogre::Real getHeight(void) const + { return mSize.y; } + /** Sets the depth (local y size) of the emitter. */ + void setDepth(Ogre::Real depth) + { + mSize.z = depth; + genAreaAxes(); + } + /** Gets the depth (local y size) of the emitter. */ + Ogre::Real getDepth(void) const + { return mSize.z; } + +protected: + /// Size of the area + Ogre::Vector3 mSize; + + /// Local axes, not normalised, their magnitude reflects area size + Ogre::Vector3 mXRange, mYRange, mZRange; + + /// Internal method for generating the area axes + void genAreaAxes(void) + { + Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); + + mXRange = mLeft * (mSize.x * 0.5f); + mYRange = mUp * (mSize.y * 0.5f); + mZRange = mDirection * (mSize.z * 0.5f); + } + + /** Internal for initializing some defaults and parameters + @return True if custom parameters need initialising + */ + bool initDefaults(const Ogre::String &t) + { + // Defaults + mDirection = Ogre::Vector3::UNIT_Z; + mUp = Ogre::Vector3::UNIT_Y; + setSize(100.0f, 100.0f, 100.0f); + mType = t; + + // Set up parameters + if(createParamDictionary(mType + "Emitter")) + { + addBaseParameters(); + Ogre::ParamDictionary *dict = getParamDictionary(); + + // Custom params + dict->addParameter(Ogre::ParameterDef("width", + "Width of the shape in world coordinates.", + Ogre::PT_REAL), + &msWidthCmd); + dict->addParameter(Ogre::ParameterDef("height", + "Height of the shape in world coordinates.", + Ogre::PT_REAL), + &msHeightCmd); + dict->addParameter(Ogre::ParameterDef("depth", + "Depth of the shape in world coordinates.", + Ogre::PT_REAL), + &msDepthCmd); + + return true; + } + return false; + } + + /// Command objects + static CmdWidth msWidthCmd; + static CmdHeight msHeightCmd; + static CmdDepth msDepthCmd; +}; +NifEmitter::CmdWidth NifEmitter::msWidthCmd; +NifEmitter::CmdHeight NifEmitter::msHeightCmd; +NifEmitter::CmdDepth NifEmitter::msDepthCmd; + +Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys); + mEmitters.push_back(emit); + return emit; +} + + class GrowFadeAffector : public Ogre::ParticleAffector { public: diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index 0d88a348e3..e1f3fd282c 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -1,8 +1,21 @@ #ifndef OENGINE_OGRE_PARTICLES_H #define OENGINE_OGRE_PARTICLES_H +#include #include +/** Factory class for NifEmitter. */ +class NifEmitterFactory : public Ogre::ParticleEmitterFactory +{ +public: + /** See ParticleEmitterFactory */ + Ogre::String getName() const + { return "Nif"; } + + /** See ParticleEmitterFactory */ + Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); +}; + /** Factory class for GrowFadeAffector. */ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index fcc4961b50..7be7137969 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -110,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ei; + for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();ei++) + OGRE_DELETE (*ei); + mEmitterFactories.clear(); + std::vector::iterator ai; for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) OGRE_DELETE (*ai); @@ -206,6 +211,13 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + + Ogre::ParticleEmitterFactory *emitter; + emitter = OGRE_NEW NifEmitterFactory(); + Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); + mEmitterFactories.push_back(emitter); + + Ogre::ParticleAffectorFactory *affector; affector = OGRE_NEW GrowFadeAffectorFactory(); Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index ea46f5ae62..962ae4f2ec 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleEmitterFactory; class ParticleAffectorFactory; } @@ -95,6 +96,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mEmitterFactories; std::vector mAffectorFactories; bool logging;