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
This commit is contained in:
timoore
2008-02-15 06:44:24 +00:00
parent b09e484492
commit ac4245013f
3 changed files with 444 additions and 446 deletions

View File

@@ -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) {

View File

@@ -1,5 +1,21 @@
// particles.cxx - classes to manage particles
// started in 2008 by Tiago Gusm<73>o, using animation.hxx as reference
// Copyright (C) 2008 Tiago Gusm<73>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 <simgear_config.h>
@@ -23,15 +39,52 @@
#include "particles.hxx"
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:"<<w[0]<<","<<w[1]<<","<<w[2]<<"\n");
}
//static members
osg::Vec3 SGGlobalParticleCallback::gravity;
osg::Vec3 SGGlobalParticleCallback::wind;
osg::Vec3 GlobalParticleCallback::gravity;
osg::Vec3 GlobalParticleCallback::wind;
osg::ref_ptr<osg::Group> SGParticles::commonRoot;
osg::ref_ptr<osgParticle::ParticleSystemUpdater> SGParticles::psu = new osgParticle::ParticleSystemUpdater;
osg::ref_ptr<osg::Geode> SGParticles::commonGeode = new osg::Geode;;
osg::ref_ptr<osg::Group> Particles::commonRoot;
osg::ref_ptr<osgParticle::ParticleSystemUpdater> Particles::psu = new osgParticle::ParticleSystemUpdater;
osg::ref_ptr<osg::Geode> Particles::commonGeode = new osg::Geode;;
osg::Group * SGParticles::appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options)
template <typename Object>
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<Particles> 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<CustomModularEmitter*>(emitter)==0) SG_LOG(SG_GENERAL, SG_ALERT, "observer error\n");
//if (dynamic_cast<CustomModularEmitter*>(emitter)==0) SG_LOG(SG_GENERAL, SG_ALERT, "observer error\n");
//align->addObserver(dynamic_cast<CustomModularEmitter*>(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:"<<configNode->getStringValue("texture","")<<"\n");
textureFile= osgDB::findFileInPath(configNode->getStringValue("texture",""),
options->getDatabasePathList());
if (configNode->hasValue("texture")) {
SG_LOG(SG_GENERAL, SG_ALERT,
"requested:"<<configNode->getStringValue("texture","")<<"\n");
textureFile= osgDB::findFileInPath(configNode->getStringValue("texture",
""),
options->getDatabasePathList());
SG_LOG(SG_GENERAL, SG_ALERT, "found:"<<textureFile<<"\n");
for(int i=0;i<options->getDatabasePathList().size();++i)
SG_LOG(SG_GENERAL, SG_ALERT, "opts:"<<options->getDatabasePathList()[i]<<"\n");
for(int i = 0; i < options->getDatabasePathList().size(); ++i)
SG_LOG(SG_GENERAL, SG_ALERT,
"opts:"<<options->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<SGPropertyNode_ptr> segments = placernode->getChildren("vertex");
if(segments.size()>1) {
osgParticle::MultiSegmentPlacer *msplacer = new osgParticle::MultiSegmentPlacer();
std::vector<SGPropertyNode_ptr> 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 (grav=="enabled") {
if(attach == "world") {
if(!callback)
callback = new SGParticles();
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<osgParticle::RadialShooter*>(emitter->getShooter()), dynamic_cast<osgParticle::RandomRateCounter*>(emitter->getCounter()), particleSys, program);
emitter->setUpdateCallback(callback);
callback.get()->setGeneralData(dynamic_cast<osgParticle::RadialShooter*>(emitter->getShooter()),
dynamic_cast<osgParticle::RandomRateCounter*>(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

View File

@@ -1,13 +1,23 @@
// particles.hxx - classes to manage particles
// started in 2008 by Tiago Gusm<73>o, using animation.hxx as reference
// Copyright (C) 2008 Tiago Gusm<73>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>
@@ -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<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 gravity;
@@ -90,216 +89,202 @@ private:
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));
}
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));
}
static osg::Group * appendParticles(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::ReaderWriter::Options* options);
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");
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
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());
}
}
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 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);
}
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);
}
void setupCounterCondition(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot)
{
counterCond = sgReadCondition(modelRoot, configNode);
}
inline void setupCounterCondition(const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
{
counterCond = sgReadCondition(modelRoot, configNode);
}
void setupCounterCondition(float counterStaticValue,
float counterStaticExtraRange)
{
this->counterStaticValue = counterStaticValue;
this->counterStaticExtraRange = counterStaticExtraRange;
}
inline 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");
}
}
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");
}
}
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 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");
}
}
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;
}
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;
}
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;
}
void setupProgramGravity(bool useGravity)
{
this->useGravity = useGravity;
}
inline void setupProgramWind(bool useWind)
{
this->useWind = useWind;
}
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
}
//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
}
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;
}
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 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 osg::Geode * getCommonGeode()
{
return commonGeode.get();
}
static inline osgParticle::ParticleSystemUpdater * getPSU()
{
return psu.get();
}
static osgParticle::ParticleSystemUpdater * getPSU()
{
return psu.get();
}
private:
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<osgParticle::ParticleSystemUpdater> psu;
static osg::ref_ptr<osg::Group> commonRoot;
static osg::ref_ptr<osg::Geode> commonGeode;
};
}
#endif
/*