From b09e484492bc634e1fbbea754c5393cc5d7f18b0 Mon Sep 17 00:00:00 2001 From: timoore Date: Fri, 15 Feb 2008 06:44:05 +0000 Subject: [PATCH] particles from Tiago_G --- simgear/scene/model/Makefile.am | 2 + simgear/scene/model/animation.cxx | 2 +- simgear/scene/model/animation.hxx | 3 + simgear/scene/model/model.cxx | 17 ++ simgear/scene/model/particles.cxx | 486 ++++++++++++++++++++++++++++++ simgear/scene/model/particles.hxx | 327 ++++++++++++++++++++ 6 files changed, 836 insertions(+), 1 deletion(-) create mode 100644 simgear/scene/model/particles.cxx create mode 100644 simgear/scene/model/particles.hxx diff --git a/simgear/scene/model/Makefile.am b/simgear/scene/model/Makefile.am index 49c69754..db102d9e 100644 --- a/simgear/scene/model/Makefile.am +++ b/simgear/scene/model/Makefile.am @@ -6,6 +6,7 @@ noinst_HEADERS = include_HEADERS = \ animation.hxx \ + particles.hxx \ location.hxx \ model.hxx \ modellib.hxx \ @@ -22,6 +23,7 @@ include_HEADERS = \ libsgmodel_a_SOURCES = \ animation.cxx \ + particles.cxx \ location.cxx \ model.cxx \ modellib.cxx \ diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 88fd835a..1bb11bee 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -186,7 +186,7 @@ read_offset_factor(const SGPropertyNode* configNode, SGExpressiond* expr, return expr; } -static SGExpressiond* +SGExpressiond* read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const char* unit, double defMin, double defMax) { diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index 70ef6726..eec16bc4 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -31,6 +31,9 @@ #undef max #endif +SGExpressiond* +read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, + const char* unit, double defMin, double defMax); ////////////////////////////////////////////////////////////////////// // Base class for animation installers diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index becc88c6..1d9606d7 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -33,6 +33,7 @@ #include "animation.hxx" #include "model.hxx" +#include "particles.hxx" SG_USING_STD(vector); @@ -250,6 +251,22 @@ sgLoad3DModel( const string &fg_root, const string &path, } } + std::vector particle_nodes; + particle_nodes = props.getChildren("particlesystem"); + for (unsigned i = 0; i < particle_nodes.size(); ++i) + { + if(i==0) + { + if (texturepath.extension() != "") + texturepath = texturepath.dir(); + + options->setDatabasePath(texturepath.str()); + if (!externalTexturePath.str().empty()) + options->getDatabasePathList().push_back(externalTexturePath.str()); + } + alignmainmodel.get()->addChild(SGParticles::appendParticles(particle_nodes[i], prop_root, options.get())); + } + if (data) { alignmainmodel->setUserData(data); data->modelLoaded(path, &props, alignmainmodel.get()); diff --git a/simgear/scene/model/particles.cxx b/simgear/scene/model/particles.cxx new file mode 100644 index 00000000..918abb51 --- /dev/null +++ b/simgear/scene/model/particles.cxx @@ -0,0 +1,486 @@ +// particles.cxx - classes to manage particles +// started in 2008 by Tiago Gusmão, using animation.hxx as reference + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "particles.hxx" + +//static members +osg::Vec3 SGGlobalParticleCallback::gravity; +osg::Vec3 SGGlobalParticleCallback::wind; + +osg::ref_ptr SGParticles::commonRoot; +osg::ref_ptr SGParticles::psu = new osgParticle::ParticleSystemUpdater; +osg::ref_ptr SGParticles::commonGeode = new osg::Geode;; + +osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options) +{ + SG_LOG(SG_GENERAL, SG_DEBUG, "Setting up a particle system!\n"); + + osgParticle::ParticleSystem *particleSys; + + //create a generic particle system + std::string type = configNode->getStringValue("type", "normal"); + if (type == "normal")particleSys= new osgParticle::ParticleSystem; + else particleSys= new osgParticle::ConnectedParticleSystem; + SGParticles *callback=NULL; //may not be used depending on the configuration + + getPSU()->addParticleSystem(particleSys); + + getPSU()->setUpdateCallback(new SGGlobalParticleCallback(modelRoot)); + + //contains counter, placer and shooter by default + osgParticle::ModularEmitter *emitter = new osgParticle::ModularEmitter; + + emitter->setParticleSystem(particleSys); + + // Set up the alignment node ("stolen" from animation.cxx) + osg::MatrixTransform *align = new osg::MatrixTransform; + osg::Matrix res_matrix; + res_matrix.makeRotate( + configNode->getFloatValue("offsets/pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS, + osg::Vec3(0, 1, 0), + configNode->getFloatValue("offsets/roll-deg", 0.0)*SG_DEGREES_TO_RADIANS, + osg::Vec3(1, 0, 0), + configNode->getFloatValue("offsets/heading-deg", 0.0)*SG_DEGREES_TO_RADIANS, + osg::Vec3(0, 0, 1)); + + osg::Matrix tmat; + tmat.makeTranslate(configNode->getFloatValue("offsets/x-m", 0.0), + configNode->getFloatValue("offsets/y-m", 0.0), + configNode->getFloatValue("offsets/z-m", 0.0)); + align->setMatrix(res_matrix*tmat); + + align->setName("particle align"); + + //if(dynamic_cast(emitter)==0) SG_LOG(SG_GENERAL, SG_ALERT, "observer error\n"); + //align->addObserver(dynamic_cast(emitter)); + + align->addChild(emitter); + + //this name can be used in the XML animation as if it was a submodel + std::string name = configNode->getStringValue("name", ""); + if(!name.empty()) align->setName(name); + + std::string attach = configNode->getStringValue("attach", "world"); + + if (attach == "local") { //local means attached to the model and not the world + osg::Geode *g = new osg::Geode; + align->addChild(g); + g->addDrawable(particleSys); + emitter->setReferenceFrame(osgParticle::Emitter::ABSOLUTE_RF); + } else + getCommonGeode()->addDrawable(particleSys); + + std::string textureFile; + + if(configNode->hasValue("texture")) { + SG_LOG(SG_GENERAL, SG_ALERT, "requested:"<getStringValue("texture","")<<"\n"); + textureFile= osgDB::findFileInPath(configNode->getStringValue("texture",""), + options->getDatabasePathList()); + SG_LOG(SG_GENERAL, SG_ALERT, "found:"<getDatabasePathList().size();++i) + SG_LOG(SG_GENERAL, SG_ALERT, "opts:"<getDatabasePathList()[i]<<"\n"); + + } + + if(textureFile.empty()) + textureFile=""; + + particleSys->setDefaultAttributes(textureFile,configNode->getBoolValue("emissive", true), + configNode->getBoolValue("lighting", false)); + + std::string alignstr = configNode->getStringValue("align","billboard"); + + if(alignstr == "fixed") + particleSys->setParticleAlignment(osgParticle::ParticleSystem::FIXED); + + const SGPropertyNode* placernode = configNode->getChild("placer"); + + if(placernode) { + std::string emitterType = placernode->getStringValue("type", "point"); + + if (emitterType == "sector") { + osgParticle::SectorPlacer *splacer = new osgParticle::SectorPlacer; + float minRadius, maxRadius, minPhi, maxPhi; + + minRadius = placernode->getFloatValue("radius-min-m",0); + maxRadius = placernode->getFloatValue("radius-max-m",1); + minPhi = placernode->getFloatValue("phi-min-deg",0) * SG_DEGREES_TO_RADIANS; + maxPhi = placernode->getFloatValue("phi-max-deg",360.0f) * SG_DEGREES_TO_RADIANS; + + splacer->setRadiusRange(minRadius, maxRadius); + splacer->setPhiRange(minPhi, maxPhi); + emitter->setPlacer(splacer); + } else if (emitterType == "segments") { + std::vector segments = placernode->getChildren("vertex"); + + if(segments.size()>1) { + osgParticle::MultiSegmentPlacer *msplacer = new osgParticle::MultiSegmentPlacer(); + float x,y,z; + + for (unsigned i = 0; i < segments.size(); ++i) { + x = segments[i]->getFloatValue("x-m",0); + y = segments[i]->getFloatValue("y-m",0); + z = segments[i]->getFloatValue("z-m",0); + msplacer->addVertex(x, y, z); + } + + emitter->setPlacer(msplacer); + } + else SG_LOG(SG_GENERAL, SG_ALERT, "Detected particle system using segment(s) with less than 2 vertices\n"); + } //else the default placer in ModularEmitter is used (PointPlacer) + } + + const SGPropertyNode* shnode = configNode->getChild("shooter"); + + if(shnode) { + float minTheta, maxTheta, minPhi, maxPhi, speed, spread; + + minTheta = shnode->getFloatValue("theta-min-deg",0) * SG_DEGREES_TO_RADIANS; + maxTheta = shnode->getFloatValue("theta-max-deg",360.0f) * SG_DEGREES_TO_RADIANS; + minPhi = shnode->getFloatValue("phi-min-deg",0)* SG_DEGREES_TO_RADIANS; + maxPhi = shnode->getFloatValue("phi-max-deg",360.0f)* SG_DEGREES_TO_RADIANS; + + osgParticle::RadialShooter *shooter = new osgParticle::RadialShooter; + emitter->setShooter(shooter); + + shooter->setThetaRange(minTheta, maxTheta); + shooter->setPhiRange(minPhi, maxPhi); + + const SGPropertyNode* speednode = shnode->getChild("speed"); + + if(speednode) { + if(speednode->hasValue("value")) { + speed = speednode->getFloatValue("value",0); + spread = speednode->getFloatValue("spread",0); + shooter->setInitialSpeedRange(speed-spread, speed+spread); + } else { + + if(!callback) + callback = new SGParticles(); + + callback->setupShooterSpeedData(speednode, modelRoot); + } + } + + const SGPropertyNode* rotspeednode = shnode->getChild("rotspeed"); + + if(rotspeednode) { + float x1,y1,z1,x2,y2,z2; + x1 = rotspeednode->getFloatValue("x-min-deg-sec",0) * SG_DEGREES_TO_RADIANS; + y1 = rotspeednode->getFloatValue("y-min-deg-sec",0) * SG_DEGREES_TO_RADIANS; + z1 = rotspeednode->getFloatValue("z-min-deg-sec",0) * SG_DEGREES_TO_RADIANS; + x2 = rotspeednode->getFloatValue("x-max-deg-sec",0) * SG_DEGREES_TO_RADIANS; + y2 = rotspeednode->getFloatValue("y-max-deg-sec",0) * SG_DEGREES_TO_RADIANS; + z2 = rotspeednode->getFloatValue("z-max-deg-sec",0) * SG_DEGREES_TO_RADIANS; + shooter->setInitialRotationalSpeedRange(osg::Vec3f(x1,y1,z1), osg::Vec3f(x2,y2,z2)); + } + } //else ModularEmitter uses the default RadialShooter + + const SGPropertyNode* counternode = configNode->getChild("counter"); + + if(counternode) { + osgParticle::RandomRateCounter *counter = new osgParticle::RandomRateCounter; + emitter->setCounter(counter); + float pps, spread; + const SGPropertyNode* ppsnode = counternode->getChild("pps"); + + if(ppsnode) { + + if(ppsnode->hasValue("value")) { + pps = ppsnode->getFloatValue("value",0); + spread = ppsnode->getFloatValue("spread",0); + counter->setRateRange(pps-spread, pps+spread); + } else { + + if(!callback) + callback = new SGParticles(); + + callback->setupCounterData(ppsnode, modelRoot); + } + } + const SGPropertyNode* conditionNode = counternode->getChild("condition"); + + if(conditionNode) { + + if(!callback) + callback = new SGParticles(); + callback->setupCounterCondition(conditionNode, modelRoot); + callback->setupCounterCondition(pps, spread); + } + } //TODO: else perhaps set higher values than default? + + const SGPropertyNode* particlenode = configNode->getChild("particle"); + + if(particlenode) { + osgParticle::Particle &particle = particleSys->getDefaultParticleTemplate(); + float r1=0, g1=0, b1=0, a1=1, r2=0, g2=0, b2=0, a2=1; + + const SGPropertyNode* startcolornode = particlenode->getChild("startcolor"); + + if(startcolornode) { + const SGPropertyNode* componentnode = startcolornode->getChild("red"); + + if(componentnode) { + + if(componentnode->hasValue("value")) + r1 = componentnode->getFloatValue("value",0); + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 0, 0); + } + } + + componentnode = startcolornode->getChild("green"); + if(componentnode) { + + if(componentnode->hasValue("value")) + g1 = componentnode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 0, 1); + } + } + + componentnode = startcolornode->getChild("blue"); + if(componentnode) { + + if(componentnode->hasValue("value")) + b1 = componentnode->getFloatValue("value",0); + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 0, 2); + } + } + + componentnode = startcolornode->getChild("alpha"); + + if(componentnode) { + + if(componentnode->hasValue("value")) + a1 = componentnode->getFloatValue("value",0); + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 0, 3); + } + } + } + + const SGPropertyNode* endcolornode = particlenode->getChild("endcolor"); + if(endcolornode) { + const SGPropertyNode* componentnode = endcolornode->getChild("red"); + + if(componentnode) { + + if(componentnode->hasValue("value")) + r2 = componentnode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 1, 0); + } + } + + componentnode = endcolornode->getChild("green"); + + if(componentnode) { + + if(componentnode->hasValue("value")) + g2 = componentnode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 1, 1); + } + } + + componentnode = endcolornode->getChild("blue"); + + if(componentnode) { + + if(componentnode->hasValue("value")) + b2 = componentnode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 1, 2); + } + } + + componentnode = endcolornode->getChild("alpha"); + if(componentnode) { + + if(componentnode->hasValue("value")) + a2 = componentnode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupColorComponent(componentnode, modelRoot, 1, 3); + } + } + } + + particle.setColorRange(osgParticle::rangev4( osg::Vec4(r1,g1,b1,a1), osg::Vec4(r2,g2,b2,a2))); + + float startsize=1, endsize=0.1f; + const SGPropertyNode* startsizenode = particlenode->getChild("startsize"); + + if(startsizenode) { + + if(startsizenode->hasValue("value")) + startsize = startsizenode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupStartSizeData(startsizenode, modelRoot); + } + } + + const SGPropertyNode* endsizenode = particlenode->getChild("endsize"); + if(endsizenode) { + + if(endsizenode->hasValue("value")) + endsize = endsizenode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupEndSizeData(endsizenode, modelRoot); + } + } + + particle.setSizeRange(osgParticle::rangef(startsize, endsize)); + + float life=5; + const SGPropertyNode* lifenode = particlenode->getChild("life-sec"); + + if(lifenode) { + + if(lifenode->hasValue("value")) + life = lifenode->getFloatValue("value",0); + + else { + + if(!callback) + callback = new SGParticles(); + + callback->setupLifeData(lifenode, modelRoot); + } + } + + particle.setLifeTime(life); + + if(particlenode->hasValue("radius-m")) + particle.setRadius(particlenode->getFloatValue("radius-m",0)); + + if(particlenode->hasValue("mass-kg")) + particle.setMass(particlenode->getFloatValue("mass-kg",0)); + + if(callback) { + callback->setupStaticColorComponent(r1, g1, b1, a1, r2, g2, b2, a2); + callback->setupStaticSizeData(startsize, endsize); + } + //particle.setColorRange(osgParticle::rangev4( osg::Vec4(r1, g1, b1, a1), osg::Vec4(r2, g2, b2, a2))); + } + + const SGPropertyNode* programnode = configNode->getChild("program"); + osgParticle::FluidProgram *program = new osgParticle::FluidProgram(); + + if(programnode) { + std::string fluid = programnode->getStringValue("fluid","air"); + + if(fluid=="air") + program->setFluidToAir(); + + else + program->setFluidToWater(); + + std::string grav = programnode->getStringValue("gravity","enabled"); + + if(grav=="enabled") { + + if(attach == "world") { + + if(!callback) + callback = new SGParticles(); + + callback->setupProgramGravity(true); + } else + program->setToGravity(); + + } else + program->setAcceleration(osg::Vec3(0,0,0)); + + std::string wind = programnode->getStringValue("wind","enabled"); + if(wind=="enabled") { + if(!callback) + callback = new SGParticles(); + callback->setupProgramWind(true); + } else + program->setWind(osg::Vec3(0,0,0)); + + align->addChild(program); + + program->setParticleSystem(particleSys); + } + else { } + + if(callback) { //this means we want property-driven changes + SG_LOG(SG_GENERAL, SG_DEBUG, "setting up particle system user data and callback\n"); + //setup data and callback + callback->setGeneralData(dynamic_cast(emitter->getShooter()), dynamic_cast(emitter->getCounter()), particleSys, program); + emitter->setUpdateCallback(callback); + } + + return align; +} diff --git a/simgear/scene/model/particles.hxx b/simgear/scene/model/particles.hxx new file mode 100644 index 00000000..bdf99a72 --- /dev/null +++ b/simgear/scene/model/particles.hxx @@ -0,0 +1,327 @@ +// particles.hxx - classes to manage particles +// started in 2008 by Tiago Gusmão, using animation.hxx as reference + +#ifndef _SG_PARTICLES_HXX +#define _SG_PARTICLES_HXX 1 +#endif + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + + +// Has anyone done anything *really* stupid, like making min and max macros? +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif + +#include "animation.hxx" + +class SGGlobalParticleCallback : public osg::NodeCallback +{ +public: + SGGlobalParticleCallback(const SGPropertyNode* modelRoot) + { + this->modelRoot=modelRoot; + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + SGQuat q = SGQuat::fromLonLatDeg(modelRoot->getFloatValue("/position/longitude-deg",0), modelRoot->getFloatValue("/position/latitude-deg",0)); + + SGMatrix m(q); + osg::Matrix om(m.data()); + osg::Vec3 v(0,0,9.81); + gravity = om.postMult(v); + + osg::Vec3 w(-modelRoot->getFloatValue("/environment/wind-from-north-fps",0) * SG_FEET_TO_METER, + -modelRoot->getFloatValue("/environment/wind-from-east-fps",0) * SG_FEET_TO_METER, 0); + wind = om.postMult(w); + + //SG_LOG(SG_GENERAL, SG_ALERT, "wind vector:"<setInitialSpeedRange(shooterValue->getValue(), shooterValue->getValue()+shooterExtraRange); + if(counterValue) + counter->setRateRange(counterValue->getValue(), counterValue->getValue()+counterExtraRange); + else if(counterCond) + counter->setRateRange(counterStaticValue, counterStaticValue + counterStaticExtraRange); + if(counterCond && !counterCond->test()) + counter->setRateRange(0,0); + bool colorchange=false; + for(int i=0;i<8;++i){ + if(colorComponents[i]){ + staticColorComponents[i] = colorComponents[i]->getValue(); + colorchange=true; + } + } + if(colorchange) + particleSys->getDefaultParticleTemplate().setColorRange(osgParticle::rangev4( osg::Vec4(staticColorComponents[0], staticColorComponents[1], staticColorComponents[2], staticColorComponents[3]), osg::Vec4(staticColorComponents[4], staticColorComponents[5], staticColorComponents[6], staticColorComponents[7]))); + if(startSizeValue) + startSize = startSizeValue->getValue(); + if(endSizeValue) + endSize = endSizeValue->getValue(); + if(startSizeValue || endSizeValue) + particleSys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(startSize, endSize)); + if(lifeValue) + particleSys->getDefaultParticleTemplate().setLifeTime(lifeValue->getValue()); + if(program){ + if(useGravity) + program->setAcceleration(SGGlobalParticleCallback::getGravityVector()); + if(useWind) + program->setWind(SGGlobalParticleCallback::getWindVector()); + } + } + + inline void setupShooterSpeedData(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + shooterValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!shooterValue){ + SG_LOG(SG_GENERAL, SG_ALERT, "shooter property error!\n"); + } + shooterExtraRange = configNode->getFloatValue("extrarange",0); + } + + inline void setupCounterData(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + counterValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!counterValue){ + SG_LOG(SG_GENERAL, SG_ALERT, "counter property error!\n"); + } + counterExtraRange = configNode->getFloatValue("extrarange",0); + } + + inline void setupCounterCondition(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + counterCond = sgReadCondition(modelRoot, configNode); + } + + inline void setupCounterCondition(float counterStaticValue, float counterStaticExtraRange) + { + this->counterStaticValue = counterStaticValue; + this->counterStaticExtraRange = counterStaticExtraRange; + } + + inline void setupStartSizeData(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + startSizeValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!startSizeValue) + { + SG_LOG(SG_GENERAL, SG_ALERT, "startSizeValue error!\n"); + } + } + + inline void setupEndSizeData(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + endSizeValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!endSizeValue){ + SG_LOG(SG_GENERAL, SG_ALERT, "startSizeValue error!\n"); + } + } + + inline void setupLifeData(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) + { + lifeValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!lifeValue){ + SG_LOG(SG_GENERAL, SG_ALERT, "lifeValue error!\n"); + } + } + + inline void setupStaticSizeData(float startSize, float endSize) + { + this->startSize=startSize; + this->endSize=endSize; + } + + + inline void setGeneralData(osgParticle::RadialShooter * shooter, osgParticle::RandomRateCounter * counter, osgParticle::ParticleSystem * particleSys, osgParticle::FluidProgram *program) + { + this->shooter = shooter; + this->counter = counter; + this->particleSys = particleSys; + this->program = program; + } + + inline void setupProgramGravity(bool useGravity) + { + this->useGravity = useGravity; + } + + inline void setupProgramWind(bool useWind) + { + this->useWind = useWind; + } + + //component: r=0, g=1, ... ; color: 0=start color, 1=end color + inline void setupColorComponent(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, int color, int component) + { + SGExpressiond *colorValue = read_value(configNode, modelRoot, "-m", -SGLimitsd::max(), SGLimitsd::max()); + if(!colorValue){ + SG_LOG(SG_GENERAL, SG_ALERT, "color property error!\n"); + } + colorComponents[(color*4)+component] = colorValue; + //number of color components = 4 + } + + inline void setupStaticColorComponent(float r1,float g1, float b1, float a1, float r2, + float g2, float b2, float a2) + { + staticColorComponents[0] = r1; + staticColorComponents[1] = g1; + staticColorComponents[2] = b1; + staticColorComponents[3] = a1; + staticColorComponents[4] = r2; + staticColorComponents[5] = g2; + staticColorComponents[6] = b2; + staticColorComponents[7] = a2; + } + + static inline osg::Group * getCommonRoot() + { + if(!commonRoot.valid()) + { + SG_LOG(SG_GENERAL, SG_DEBUG, "Particle common root called!\n"); + commonRoot = new osg::Group; + commonRoot.get()->setName("common particle system root"); + commonGeode.get()->setName("common particle system geode"); + commonRoot.get()->addChild(commonGeode.get()); + commonRoot.get()->addChild(psu.get()); + } + return commonRoot.get(); + } + + static inline osg::Geode * getCommonGeode() + { + return commonGeode.get(); + } + + static inline osgParticle::ParticleSystemUpdater * getPSU() + { + return psu.get(); + } + +private: + float shooterExtraRange; + float counterExtraRange; + SGExpressiond * shooterValue; + SGExpressiond * counterValue; + SGExpressiond * colorComponents[8]; + SGExpressiond * startSizeValue; + SGExpressiond * endSizeValue; + SGExpressiond * lifeValue; + SGCondition * counterCond; + osg::MatrixTransform *refFrame; + float staticColorComponents[8]; + float startSize; + float endSize; + float counterStaticValue; + float counterStaticExtraRange; + osgParticle::RadialShooter * shooter; + osgParticle::RandomRateCounter * counter; + osgParticle::ParticleSystem * particleSys; + osgParticle::FluidProgram * program; + bool useGravity; + bool useWind; + static osg::ref_ptr psu; + static osg::ref_ptr commonRoot; + static osg::ref_ptr commonGeode; +}; + + +/* +class CustomModularEmitter : public osgParticle::ModularEmitter, public osg::Observer +{ +public: + +virtual void objectDeleted (void *) +{ +SG_LOG(SG_GENERAL, SG_ALERT, "object deleted!\n"); + +SGParticles::getCommonRoot()->removeChild(this->getParticleSystem()->getParent(0)); +SGParticles::getPSU()->removeParticleSystem(this->getParticleSystem()); +} + + +// ~CustomModularEmitter() +// { +// SG_LOG(SG_GENERAL, SG_ALERT, "object deleted!\n"); +// +// SGParticles::getCommonRoot()->removeChild(this->getParticleSystem()->getParent(0)); +// SGParticles::getPSU()->removeParticleSystem(this->getParticleSystem()); +// } +}; +*/ -- 2.39.5