// 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 <osg/ref_ptr>
-#include <osg/Group>
-#include <osg/Node>
-#include <osg/NodeVisitor>
-#include <osg/Texture2D>
#include <osgParticle/SmokeTrailEffect>
#include <osgParticle/Particle>
#include <osgParticle/ModularEmitter>
-#include <osgParticle/ParticleSystemUpdater>
-#include <osgParticle/ParticleSystem>
-#include <osg/MatrixTransform>
#include <osgDB/ReaderWriter>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osg/Notify>
#include <osg/Vec3>
+namespace osg
+{
+class Group;
+class MatrixTransform;
+class Node;
+class NodeVisitor;
+}
+
+namespace osgParticle
+{
+class ParticleSystem;
+class ParticleSystemUpdater;
+}
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/structure/SGExpression.hxx>
+#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGQuat.hxx>
#include <simgear/math/SGMatrix.hxx>
#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<float> q = SGQuat<float>::fromLonLatDeg(modelRoot->getFloatValue("/position/longitude-deg",0), modelRoot->getFloatValue("/position/latitude-deg",0));
-
- SGMatrix<float> 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:"<<w[0]<<","<<w[1]<<","<<w[2]<<"\n");
- }
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
static const osg::Vec3 &getGravityVector()
{
return wind;
}
+ static void setSwitch(const SGPropertyNode* n)
+ {
+ enabledNode = n;
+ }
+
+ static bool getEnabled()
+ {
+ return enabled;
+ }
+private:
static osg::Vec3 gravity;
static osg::Vec3 wind;
-private:
-
- const SGPropertyNode* modelRoot;
+ SGConstPropertyNode_ptr modelRoot;
+ static SGConstPropertyNode_ptr enabledNode;
+ static bool enabled;
};
-class SGParticles : public osg::NodeCallback
+class Particles : public osg::NodeCallback
{
public:
- SGParticles( ) :
- 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));
- }
-
- static osg::Group * appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options);
-
- virtual void 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(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();
-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();
+
+ static osg::Geode * getCommonGeode()
+ {
+ return commonGeode.get();
+ }
+
+ static osgParticle::ParticleSystemUpdater * getPSU()
+ {
+ return psu.get();
+ }
+
+ static void setFrozen(bool e) { _frozen = e; }
+
+ /**
+ * Set and get the wind vector for particles in the
+ * atmosphere. This vector is in the Z-up Y-north frame, and the
+ * magnitude is the velocity in meters per second.
+ */
+ static void setWindVector(const osg::Vec3& wind) { _wind = wind; }
+ static void setWindFrom(const double from_deg, const double speed_kt) {
+ double map_rad = -from_deg * SG_DEGREES_TO_RADIANS;
+ double speed_mps = speed_kt * SG_KT_TO_MPS;
+ _wind[0] = cos(map_rad) * speed_mps;
+ _wind[1] = sin(map_rad) * speed_mps;
+ _wind[2] = 0.0;
+ }
+ static const osg::Vec3& getWindVector() { return _wind; }
+protected:
float shooterExtraRange;
float counterExtraRange;
- SGExpressiond * shooterValue;
- SGExpressiond * counterValue;
- SGExpressiond * colorComponents[8];
- SGExpressiond * startSizeValue;
- SGExpressiond * endSizeValue;
- SGExpressiond * lifeValue;
- SGCondition * counterCond;
- osg::MatrixTransform *refFrame;
+ SGSharedPtr<SGExpressiond> shooterValue;
+ SGSharedPtr<SGExpressiond> counterValue;
+ SGSharedPtr<SGExpressiond> colorComponents[8];
+ SGSharedPtr<SGExpressiond> startSizeValue;
+ SGSharedPtr<SGExpressiond> endSizeValue;
+ SGSharedPtr<SGExpressiond> lifeValue;
+ SGSharedPtr<SGCondition> counterCond;
float staticColorComponents[8];
float startSize;
float endSize;
float counterStaticValue;
float counterStaticExtraRange;
- osgParticle::RadialShooter * shooter;
- osgParticle::RandomRateCounter * counter;
- osgParticle::ParticleSystem * particleSys;
- osgParticle::FluidProgram * program;
+ osg::ref_ptr<osgParticle::RadialShooter> shooter;
+ osg::ref_ptr<osgParticle::RandomRateCounter> counter;
+ osg::ref_ptr<osgParticle::ParticleSystem> particleSys;
+ osg::ref_ptr<osgParticle::FluidProgram> program;
+ osg::ref_ptr<osg::MatrixTransform> particleFrame;
+
bool useGravity;
bool useWind;
+ static bool _frozen;
static osg::ref_ptr<osgParticle::ParticleSystemUpdater> psu;
static osg::ref_ptr<osg::Group> commonRoot;
static osg::ref_ptr<osg::Geode> commonGeode;
+ static osg::Vec3 _wind;
};
+}
+#endif
/*