From: timoore Date: Fri, 15 Feb 2008 06:44:24 +0000 (+0000) Subject: Cleanup of particles contribution X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=ac4245013fe74b574de9491f08fa0867d2d3150b;p=simgear.git Cleanup of particles contribution Put particles classes inside simgear namespace Refactored some redundant code Reworked local frame math to use OSG math classes as much as possible --- diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 1d9606d7..fd4962c0 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -37,6 +37,8 @@ SG_USING_STD(vector); +using namespace simgear; + osg::Texture2D* SGLoadTexture2D(bool staticTexture, const std::string& path, const osgDB::ReaderWriter::Options* options, @@ -264,7 +266,9 @@ sgLoad3DModel( const string &fg_root, const string &path, if (!externalTexturePath.str().empty()) options->getDatabasePathList().push_back(externalTexturePath.str()); } - alignmainmodel.get()->addChild(SGParticles::appendParticles(particle_nodes[i], prop_root, options.get())); + alignmainmodel.get()->addChild(Particles::appendParticles(particle_nodes[i], + prop_root, + options.get())); } if (data) { diff --git a/simgear/scene/model/particles.cxx b/simgear/scene/model/particles.cxx index 918abb51..246498ad 100644 --- a/simgear/scene/model/particles.cxx +++ b/simgear/scene/model/particles.cxx @@ -1,5 +1,21 @@ // particles.cxx - classes to manage particles // started in 2008 by Tiago Gusmão, using animation.hxx as reference +// Copyright (C) 2008 Tiago Gusmão +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// #ifdef HAVE_CONFIG_H # include @@ -23,15 +39,52 @@ #include "particles.hxx" -//static members -osg::Vec3 SGGlobalParticleCallback::gravity; -osg::Vec3 SGGlobalParticleCallback::wind; +namespace simgear +{ +void GlobalParticleCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + SGQuatd q + = SGQuatd::fromLonLatDeg(modelRoot->getFloatValue("/position/longitude-deg",0), + modelRoot->getFloatValue("/position/latitude-deg",0)); + osg::Matrix om(q.osg()); + osg::Vec3 v(0,0,9.81); + gravity = om.preMult(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.preMult(w); + + //SG_LOG(SG_GENERAL, SG_ALERT, "wind vector:"< 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) +//static members +osg::Vec3 GlobalParticleCallback::gravity; +osg::Vec3 GlobalParticleCallback::wind; + +osg::ref_ptr Particles::commonRoot; +osg::ref_ptr Particles::psu = new osgParticle::ParticleSystemUpdater; +osg::ref_ptr Particles::commonGeode = new osg::Geode;; + +template +class PointerGuard{ +public: + PointerGuard() : _ptr(0) {} + Object* get() { return _ptr; } + Object* operator () () + { + if (!_ptr) + _ptr = new Object; + return _ptr; + } +private: + Object* _ptr; +}; + +osg::Group * Particles::appendParticles(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot, + const osgDB::ReaderWriter::Options* + options) { SG_LOG(SG_GENERAL, SG_DEBUG, "Setting up a particle system!\n"); @@ -39,20 +92,22 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr //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 + if (type == "normal") + particleSys = new osgParticle::ParticleSystem; + else + particleSys = new osgParticle::ConnectedParticleSystem; + //may not be used depending on the configuration + PointerGuard callback; getPSU()->addParticleSystem(particleSys); - - getPSU()->setUpdateCallback(new SGGlobalParticleCallback(modelRoot)); - + getPSU()->setUpdateCallback(new GlobalParticleCallback(modelRoot)); //contains counter, placer and shooter by default - osgParticle::ModularEmitter *emitter = new osgParticle::ModularEmitter; + osgParticle::ModularEmitter* emitter = new osgParticle::ModularEmitter; emitter->setParticleSystem(particleSys); // Set up the alignment node ("stolen" from animation.cxx) + // XXX Order of rotations is probably not correct. osg::MatrixTransform *align = new osg::MatrixTransform; osg::Matrix res_matrix; res_matrix.makeRotate( @@ -65,58 +120,62 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr 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); + 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"); + //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); - + 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; + osg::Geode* g = new osg::Geode; align->addChild(g); g->addDrawable(particleSys); emitter->setReferenceFrame(osgParticle::Emitter::ABSOLUTE_RF); - } else + } 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()); + 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"); + for(int i = 0; i < options->getDatabasePathList().size(); ++i) + SG_LOG(SG_GENERAL, SG_ALERT, + "opts:"<getDatabasePathList()[i]<<"\n"); } - if(textureFile.empty()) + if (textureFile.empty()) textureFile=""; - particleSys->setDefaultAttributes(textureFile,configNode->getBoolValue("emissive", true), - configNode->getBoolValue("lighting", false)); + particleSys->setDefaultAttributes(textureFile, + configNode->getBoolValue("emissive", + true), + configNode->getBoolValue("lighting", + false)); - std::string alignstr = configNode->getStringValue("align","billboard"); + std::string alignstr = configNode->getStringValue("align", "billboard"); - if(alignstr == "fixed") + if (alignstr == "fixed") particleSys->setParticleAlignment(osgParticle::ParticleSystem::FIXED); const SGPropertyNode* placernode = configNode->getChild("placer"); - if(placernode) { + if (placernode) { std::string emitterType = placernode->getStringValue("type", "point"); if (emitterType == "sector") { @@ -125,17 +184,20 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr 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; + 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(); + 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) { @@ -144,22 +206,26 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr 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 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) { + 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; + 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; + maxPhi = (shnode->getFloatValue("phi-max-deg",360.0f) + * SG_DEGREES_TO_RADIANS); osgParticle::RadialShooter *shooter = new osgParticle::RadialShooter; emitter->setShooter(shooter); @@ -169,23 +235,19 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr const SGPropertyNode* speednode = shnode->getChild("speed"); - if(speednode) { - if(speednode->hasValue("value")) { + 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); + callback()->setupShooterSpeedData(speednode, modelRoot); } } const SGPropertyNode* rotspeednode = shnode->getChild("rotspeed"); - if(rotspeednode) { + 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; @@ -199,236 +261,146 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr const SGPropertyNode* counternode = configNode->getChild("counter"); - if(counternode) { - osgParticle::RandomRateCounter *counter = new osgParticle::RandomRateCounter; + if (counternode) { + osgParticle::RandomRateCounter* counter + = new osgParticle::RandomRateCounter; emitter->setCounter(counter); float pps, spread; const SGPropertyNode* ppsnode = counternode->getChild("pps"); - if(ppsnode) { + if (ppsnode) { - if(ppsnode->hasValue("value")) { + 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); + 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); + const SGPropertyNode* conditionNode + = counternode->getChild("condition"); + if (conditionNode) { + 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(); + 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")) + 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); - } + else + 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); - } + if (componentnode) { + if (componentnode->hasValue("value")) + g1 = componentnode->getFloatValue("value", 0); + else + callback()->setupColorComponent(componentnode, modelRoot, + 0, 1); } - componentnode = startcolornode->getChild("blue"); - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) b1 = componentnode->getFloatValue("value",0); - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 0, 2); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 0, 2); } - componentnode = startcolornode->getChild("alpha"); - - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) a1 = componentnode->getFloatValue("value",0); - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 0, 3); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 0, 3); } } - const SGPropertyNode* endcolornode = particlenode->getChild("endcolor"); - if(endcolornode) { + if (endcolornode) { const SGPropertyNode* componentnode = endcolornode->getChild("red"); - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) r2 = componentnode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 1, 0); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 1, 0); } - componentnode = endcolornode->getChild("green"); - - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) g2 = componentnode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 1, 1); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 1, 1); } - componentnode = endcolornode->getChild("blue"); - - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) b2 = componentnode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 1, 2); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 1, 2); } - componentnode = endcolornode->getChild("alpha"); - if(componentnode) { - - if(componentnode->hasValue("value")) + if (componentnode) { + if (componentnode->hasValue("value")) a2 = componentnode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupColorComponent(componentnode, modelRoot, 1, 3); - } + else + callback()->setupColorComponent(componentnode, modelRoot, + 1, 3); } } - - particle.setColorRange(osgParticle::rangev4( osg::Vec4(r1,g1,b1,a1), osg::Vec4(r2,g2,b2,a2))); + 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")) + if (startsizenode) { + if (startsizenode->hasValue("value")) startsize = startsizenode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupStartSizeData(startsizenode, modelRoot); - } + else + callback()->setupStartSizeData(startsizenode, modelRoot); } - const SGPropertyNode* endsizenode = particlenode->getChild("endsize"); - if(endsizenode) { - - if(endsizenode->hasValue("value")) + if (endsizenode) { + if (endsizenode->hasValue("value")) endsize = endsizenode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupEndSizeData(endsizenode, modelRoot); - } + else + 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")) + if (lifenode) { + if (lifenode->hasValue("value")) life = lifenode->getFloatValue("value",0); - - else { - - if(!callback) - callback = new SGParticles(); - - callback->setupLifeData(lifenode, modelRoot); - } + else + callback()->setupLifeData(lifenode, modelRoot); } particle.setLifeTime(life); - - if(particlenode->hasValue("radius-m")) + if (particlenode->hasValue("radius-m")) particle.setRadius(particlenode->getFloatValue("radius-m",0)); - - if(particlenode->hasValue("mass-kg")) + 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); + if (callback.get()) { + callback.get()->setupStaticColorComponent(r1, g1, b1, a1, + r2, g2, b2, a2); + callback.get()->setupStaticSizeData(startsize, endsize); } //particle.setColorRange(osgParticle::rangev4( osg::Vec4(r1, g1, b1, a1), osg::Vec4(r2, g2, b2, a2))); } @@ -436,10 +408,10 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr const SGPropertyNode* programnode = configNode->getChild("program"); osgParticle::FluidProgram *program = new osgParticle::FluidProgram(); - if(programnode) { + if (programnode) { std::string fluid = programnode->getStringValue("fluid","air"); - if(fluid=="air") + if (fluid=="air") program->setFluidToAir(); else @@ -447,26 +419,19 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr std::string grav = programnode->getStringValue("gravity","enabled"); - if(grav=="enabled") { - - if(attach == "world") { - - if(!callback) - callback = new SGParticles(); + if (grav=="enabled") { - callback->setupProgramGravity(true); - } else + if (attach == "world") + 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 + if (wind=="enabled") + callback()->setupProgramWind(true); + else program->setWind(osg::Vec3(0,0,0)); align->addChild(program); @@ -475,12 +440,56 @@ osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPr } else { } - if(callback) { //this means we want property-driven changes + if (callback.get()) { //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); + callback.get()->setGeneralData(dynamic_cast(emitter->getShooter()), + dynamic_cast(emitter->getCounter()), + particleSys, program); + emitter->setUpdateCallback(callback.get()); } return align; } + +void Particles::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + //SG_LOG(SG_GENERAL, SG_ALERT, "callback!\n"); + + if (shooterValue) + shooter->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(GlobalParticleCallback::getGravityVector()); + if (useWind) + program->setWind(GlobalParticleCallback::getWindVector()); + } +} +} // namespace simgear diff --git a/simgear/scene/model/particles.hxx b/simgear/scene/model/particles.hxx index bdf99a72..5beb7fe8 100644 --- a/simgear/scene/model/particles.hxx +++ b/simgear/scene/model/particles.hxx @@ -1,13 +1,23 @@ // particles.hxx - classes to manage particles -// started in 2008 by Tiago Gusmão, using animation.hxx as reference +// Copyright (C) 2008 Tiago Gusmão +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// #ifndef _SG_PARTICLES_HXX #define _SG_PARTICLES_HXX 1 -#endif - -#ifndef __cplusplus -# error This library requires C++ -#endif #include #include @@ -46,30 +56,19 @@ #include "animation.hxx" -class SGGlobalParticleCallback : public osg::NodeCallback +namespace simgear +{ + +class GlobalParticleCallback : public osg::NodeCallback { public: - SGGlobalParticleCallback(const SGPropertyNode* modelRoot) + GlobalParticleCallback(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(); - } + Particles() : + shooterValue(NULL), + counterValue(NULL), + startSizeValue(NULL), + endSizeValue(NULL), + lifeValue(NULL), + refFrame(NULL), + program(NULL), + useGravity(false), + useWind(false), + counterCond(NULL) + { + memset(colorComponents, 0, sizeof(colorComponents)); + } -private: + static osg::Group * appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + 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); + } + + 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); + } + + void setupCounterCondition(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) + { + counterCond = sgReadCondition(modelRoot, configNode); + } + + void setupCounterCondition(float counterStaticValue, + float counterStaticExtraRange) + { + this->counterStaticValue = counterStaticValue; + this->counterStaticExtraRange = counterStaticExtraRange; + } + + 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"); + } + } + + 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"); + } + } + + 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"); + } + } + + void setupStaticSizeData(float startSize, float endSize) + { + this->startSize=startSize; + this->endSize=endSize; + } + + + 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; + } + + void setupProgramGravity(bool useGravity) + { + this->useGravity = useGravity; + } + + void setupProgramWind(bool useWind) + { + this->useWind = useWind; + } + + //component: r=0, g=1, ... ; color: 0=start color, 1=end color + 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 + } + + 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 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 osg::Geode * getCommonGeode() + { + return commonGeode.get(); + } + + static osgParticle::ParticleSystemUpdater * getPSU() + { + return psu.get(); + } + +protected: float shooterExtraRange; float counterExtraRange; - SGExpressiond * shooterValue; - SGExpressiond * counterValue; - SGExpressiond * colorComponents[8]; - SGExpressiond * startSizeValue; - SGExpressiond * endSizeValue; - SGExpressiond * lifeValue; - SGCondition * counterCond; - osg::MatrixTransform *refFrame; + 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; + 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; }; +} +#endif /*