From 9ba7505d1eb094f78ccbccacf6dfcee9ecf2ed4b Mon Sep 17 00:00:00 2001
From: Robert Osfield class osgParticle::AccelOperator
An operator class that applies a constant acceleration to the particles
+
+
+Inheritance:
+
+
+
+
+
+
Public Methods
META_Object(AccelOperator)
+
inline AccelOperator()
+
inline AccelOperator(const AccelOperator ©, const osg::CopyOp ©op)
+
inline const osg::Vec3& getAcceleration() const
+
inline void setAcceleration(const osg::Vec3 &v)
+
inline void setToGravity(float scale)
+
inline void operate(Particle* P, double dt)
+
inline void beginOperate(Program* prg)
+
An operator class that applies a constant acceleration to the particles+
scale parameter.
+Alphabetic index HTML hierarchy of classes or Java
An abstract placer base class for placers which need a center point+
An abstract placer base class for placers which need a center point+
Alphabetic index HTML hierarchy of classes or Java
Alphabetic index HTML hierarchy of classes or Java
An abstract base class for particle emitters.+
An abstract base class for particle emitters. +Descendant classes must override the+emit()method to generate new particles by +calling theParticleSystem::createParticle()method on the particle system associated +to the emitter.
Alphabetic index HTML hierarchy of classes or Java
An operator that simulates the friction of a fluid.+
An operator that simulates the friction of a fluid.
+By using this operator you can let the particles move in a fluid of a given density
+and viscosity. There are two functions to quickly setup the parameters for pure water
+and air. You can decide whether to compute the forces using the particle's physical
+radius or another value, by calling the setOverrideRadius() method.
+Alphabetic index HTML hierarchy of classes or Java
An operator that applies a constant force to the particles.+
An operator that applies a constant force to the particles. +Remember that if the mass of particles is expressed in kg and the lengths are +expressed in meters, then the force should be expressed in Newtons.+
Alphabetic index HTML hierarchy of classes or Java
Alphabetic index Hierarchy of classes
An abstract base class for implementing interpolators+
An abstract base class for implementing interpolators+
Alphabetic index HTML hierarchy of classes or Java
A linear interpolator+
A linear interpolator+
Alphabetic index HTML hierarchy of classes or Java
An emitter class that holds three objects to control the creation of particles.+
An emitter class that holds three objects to control the creation of particles. +These objects are a counter, a placer and a shooter. +The counter controls the number of particles to be emitted at each frame; +the placer must initialize the particle's position vector, while the shooter initializes +its velocity vector. +You can use the predefined counter/placer/shooter classes, or you can create your own.+
Alphabetic index HTML hierarchy of classes or Java
A program class for performing operations on particles using a sequence of operators.+
A program class for performing operations on particles using a sequence of operators. +To use a+ModularProgramyou have to create someOperatorobjects and +add them to the program. +All operators will be applied to each particle in the same order they've been added to the program.
Alphabetic index HTML hierarchy of classes or Java
A polyline-shaped particle placer.+
A polyline-shaped particle placer. +This placer class sets the position of incoming particles by choosing a random point on the +specified sequence of connected segments.+
ModularEmitter, do not call this method manually.
+Alphabetic index HTML hierarchy of classes or Java
Range of osg::Vec4s+ + +
Range of osg::Vec4s+
Alphabetic index HTML hierarchy of classes or Java
An abstract base class used by ModularProgram to perform operations on particles before they are updated.
+operate() method.
+An abstract base class used by+ModularProgramto perform operations on particles before they are updated. +To implement a new operator, derive from this class and override theoperate()method. +You should also override thebeginOperate()method to query the calling program for the reference frame +used, and initialize the right transformations if needed.
ModularProgram objects to perform some operations
+on the particles. You must override it in descendant classes. Common operations
+consist of modifying the particle's velocity vector. The dt parameter is
+the time elapsed from last operation.
+operate() method.
+Overriding this method could be necessary to query the calling Program object
+for the current reference frame. If the reference frame is RELATIVE_TO_PARENTS, then your
+class should prepare itself to do all operations in local coordinates.
+Alphabetic index HTML hierarchy of classes or Java
Implementation of a particle.+
isAlive() method will still return true until the particle is updated again
+1 / getMass()
+Implementation of a particle. +Objects of this class are particles, they have some graphical properties +and some physical properties. Particles are created by emitters and then placed +into Particle Systems, where they live and get updated at each frame. +Particles can either live forever (lifeTime < 0), or die after a specified +time (lifeTime >= 0). For each property which is defined as a range of values, a +"current" value will be evaluated at each frame by interpolating the min +and max values so that curr_value = min when t == 0, and +curr_value = max when t == lifeTime. +You may customize the interpolator objects to achieve any kind of transition. +If you want the particle to live forever, set its lifetime to any value <= 0; +in that case, no interpolation is done to compute real-time properties, and only +minimum values are used.+
ParticleSystem::update(); it
+updates the graphical properties of the particle for the current time,
+checks whether the particle is still alive, and then updates its position
+by computing P = P + V * dt (where P is the position and V is the velocity).
+isAlive() method will still
+return true until the particle is updated again
+1 / getMass()
+Alphabetic index HTML hierarchy of classes or Java
A common base interface for those classes which need to do something on particles.+
A common base interface for those classes which need to do something on particles. Such classes +are, for example,+Emitter(particle generation) andProgram(particle animation). +This class holds some properties, like a reference frame and a reference to aParticleSystem; +descendant classes should process the particles taking into account the reference frame, computing the right +transformations when needed.
Alphabetic index HTML hierarchy of classes or Java
The heart of this class library; its purpose is to hold a set of particles and manage particle creation, update, rendering and destruction.+
ptemplate is null)
+StateAttribute's in one call.
+The heart of this class library; its purpose is to hold a set of particles and manage particle creation, update, rendering and destruction. +You can add this drawable to any+Geodeas you usually do with other +Drawableclasses. Each instance ofParticleSystemis a separate set of +particles; it provides the interface for creating particles and iterating +through them (see theEmitterandProgramclasses).
ptemplate is null)
+StateAttribute's in one call.
+If texturefile is empty, then texturing is turned off.
+ParticleSystemUpdater instead.
+setDefaultAttributes, then the particle
+system will fall into a transparent bin.
+Alphabetic index HTML hierarchy of classes or Java
A useful node class for updating particle systems automatically.+
A useful node class for updating particle systems automatically. +When a+ParticleSystemUpdateris traversed by a cull visitor, it calls the +update()method on the specified particle systems. You should place this updater +AFTER other nodes like emitters and programs.
Alphabetic index HTML hierarchy of classes or Java
An abstract base class for implementing particle placers.+
An abstract base class for implementing particle placers. A placer is an object which take
+a particle as input, and places it somewhere by setting its position vector. Placer objects are
+used by the ModularEmitter class as part of the particle emission process.
+Alphabetic index HTML hierarchy of classes or Java
A point-shaped particle placer.+
A point-shaped particle placer.
+This placer class uses the center point defined in its base class CenteredPlacer
+to place there all incoming particles.
+ModularEmitter and should not be called
+manually.
+Alphabetic index HTML hierarchy of classes or Java
An abstract ParticleProcessor descendant for modifying particles "on the fly" during the cull traversal.
+ParticleProcessor::process().
+An abstract+ParticleProcessordescendant for modifying particles "on the fly" +during the cull traversal. +Descendants of this class must implement theexecute()method, which should iterate +through all particles in the linked particle system and modify them somehow +(usually updating their velocity vector).
ParticleProcessor::process(). Do not call this method by yourself.
+Alphabetic index HTML hierarchy of classes or Java
A shooter class that shoots particles radially.+
A shooter class that shoots particles radially. +This shooter computes the velocity vector of incoming particles by choosing a +random direction and a random speed. Both direction and speed are chosen within +specified ranges. The direction is defined by two angles: theta, which +is the angle between the velocity vector and the Z axis, and phi, which is +the angle between the X axis and the velocity vector projected onto the X-Y plane.+
Alphabetic index HTML hierarchy of classes or Java
Alphabetic index HTML hierarchy of classes or Java
A sector-shaped particle placer.+
A sector-shaped particle placer.
+This placer sets the initial position of incoming particle by choosing a random position
+within a circular sector; this sector is defined by three parameters: a center point,
+which is inherited directly from osgParticle::CenteredPlacer, a range of values
+for radius, and a range of values for the central angle (sometimes called phi).
+Alphabetic index HTML hierarchy of classes or Java
A segment-shaped particle placer.+
A segment-shaped particle placer.
+To use this placer you have to define a segment, by setting its two vertices (A and B);
+when an emitter requests a SegmentPlacer to place a particle, the position is chosen randomly
+within that segment.
+ModularEmitter, do not call it manually.
+Alphabetic index HTML hierarchy of classes or Java
An abstract base class used by ModularEmitter to "shoot" the particles after they have been placed.+
An abstract base class used by ModularEmitter to "shoot" the particles after they have been placed.
+Descendants of this class must override the shoot() method.
+P, leaving other
+attributes unchanged.
+Alphabetic index HTML hierarchy of classes or Java
Alphabetic index HTML hierarchy of classes or Java
ModularProgram to perform operations on particles before they are updated.
+ParticleProcessor descendant for modifying particles "on the fly" during the cull traversal.
+Alphabetic index HTML hierarchy of classes or Java
A simple struct template useful to store ranges of values as min/max pairs.+ +
+A simple struct template useful to store ranges of values as min/max pairs. +This struct template helps storing min/max ranges for values of any kind; class+T_is +the type of values to be stored, and it must support operationsT_ + T_,T_ - T_, +andT_ * float, otherwise theget_random()method will not compile. +This struct could be extended to customize the random number generator (now it uses only +std::rand()).
Alphabetic index HTML hierarchy of classes or Java
Range of floats+ + +
Range of floats+
Alphabetic index HTML hierarchy of classes or Java
Range of osg::Vec2s+ + +
Range of osg::Vec2s+
Alphabetic index HTML hierarchy of classes or Java
Range of osg::Vec3s+ + +
Range of osg::Vec3s+
Alphabetic index HTML hierarchy of classes or Java
scale parameter.
+ */
+ inline void setToGravity(float scale = 1);
+
+ /// Apply the acceleration to a particle. Do not call this method manually.
+ inline void operate(Particle *P, double dt);
+
+ /// Perform some initializations. Do not call this method manually.
+ inline void beginOperate(Program *prg);
+
+ protected:
+ virtual ~AccelOperator() {}
+ AccelOperator &operator=(const AccelOperator &) { return *this; }
+
+ private:
+ osg::Vec3 accel_;
+ osg::Vec3 xf_accel_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline AccelOperator::AccelOperator()
+ : Operator(), accel_(0, 0, 0)
+ {
+ }
+
+ inline AccelOperator::AccelOperator(const AccelOperator ©, const osg::CopyOp ©op)
+ : Operator(copy, copyop), accel_(copy.accel_)
+ {
+ }
+
+ inline const osg::Vec3 &AccelOperator::getAcceleration() const
+ {
+ return accel_;
+ }
+
+ inline void AccelOperator::setAcceleration(const osg::Vec3 &v)
+ {
+ accel_ = v;
+ }
+
+ inline void AccelOperator::setToGravity(float scale)
+ {
+ accel_.set(0, 0, -9.80665f * scale);
+ }
+
+ inline void AccelOperator::operate(Particle *P, double dt)
+ {
+ P->addVelocity(xf_accel_ * dt);
+ }
+
+ inline void AccelOperator::beginOperate(Program *prg)
+ {
+ if (prg->getReferenceFrame() == ModularProgram::RELATIVE_TO_PARENTS) {
+ xf_accel_ = prg->rotateLocalToWorld(accel_);
+ } else {
+ xf_accel_ = accel_;
+ }
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/CenteredPlacer b/include/osgParticle/CenteredPlacer
new file mode 100644
index 000000000..b950f44e8
--- /dev/null
+++ b/include/osgParticle/CenteredPlacer
@@ -0,0 +1,74 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_CENTEREDPLACER_
+#define OSGPARTICLE_CENTEREDPLACER_ 1
+
+#include emit() method to generate new particles by
+ calling the ParticleSystem::createParticle() method on the particle system associated
+ to the emitter.
+ */
+ class OSGPARTICLE_EXPORT Emitter: public ParticleProcessor {
+ public:
+ Emitter();
+ Emitter(const Emitter ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "Emitter"; }
+ virtual bool isSameKindAs(const osg::Object *obj) { return dynamic_castsetOverrideRadius() method.
+ */
+ class OSGPARTICLE_EXPORT FluidFrictionOperator: public Operator {
+ public:
+
+ FluidFrictionOperator();
+ FluidFrictionOperator(const FluidFrictionOperator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(FluidFrictionOperator);
+
+ /// Get the density of the fluid.
+ inline float getFluidDensity() const;
+
+ /// Set the density of the fluid.
+ inline void setFluidDensity(float d);
+
+ /// Get the viscosity of the fluid.
+ inline float getFluidViscosity() const;
+
+ /// Set the viscosity of the fluid.
+ inline void setFluidViscosity(float v);
+
+ /// Get the overriden radius value.
+ inline float getOverrideRadius() const;
+
+ /// Set the overriden radius value (pass 0 if you want to use particle's radius).
+ inline void setOverrideRadius(float r);
+
+ /// Set the fluid parameters as for air (20°C temperature).
+ inline void setFluidToAir();
+
+ /// Set the fluid parameters as for pure water (20°C temperature).
+ inline void setFluidToWater();
+
+ /// Apply the friction forces to a particle. Do not call this method manually.
+ void operate(Particle *P, double dt);
+
+ /// Perform some initializations. Do not call this method manually.
+ inline void beginOperate(Program *prg);
+
+ protected:
+ virtual ~FluidFrictionOperator() {}
+ FluidFrictionOperator &operator=(const FluidFrictionOperator &) { return *this; }
+
+ private:
+ float A_;
+ float B_;
+ float density_;
+ float viscosity_;
+ float ovr_rad_;
+ Program *current_program_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline float FluidFrictionOperator::getFluidDensity() const
+ {
+ return density_;
+ }
+
+ inline float FluidFrictionOperator::getFluidViscosity() const
+ {
+ return viscosity_;
+ }
+
+ inline void FluidFrictionOperator::setFluidDensity(float d)
+ {
+ density_ = d;
+ B_ = 0.2f * osg::PI * density_;
+ }
+
+ inline void FluidFrictionOperator::setFluidViscosity(float v)
+ {
+ viscosity_ = v;
+ A_ = 6 * osg::PI * viscosity_;
+ }
+
+ inline void FluidFrictionOperator::setFluidToAir()
+ {
+ setFluidViscosity(1.8e-5f);
+ setFluidDensity(1.2929f);
+ }
+
+ inline void FluidFrictionOperator::setFluidToWater()
+ {
+ setFluidViscosity(1.002e-3f);
+ setFluidDensity(1.0f);
+ }
+
+ inline float FluidFrictionOperator::getOverrideRadius() const
+ {
+ return ovr_rad_;
+ }
+
+ inline void FluidFrictionOperator::setOverrideRadius(float r)
+ {
+ ovr_rad_ = r;
+ }
+
+ inline void FluidFrictionOperator::beginOperate(Program *prg)
+ {
+ current_program_ = prg;
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/ForceOperator b/include/osgParticle/ForceOperator
new file mode 100644
index 000000000..6da553c38
--- /dev/null
+++ b/include/osgParticle/ForceOperator
@@ -0,0 +1,89 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_FORCEOPERATOR_
+#define OSGPARTICLE_FORCEOPERATOR_ 1
+
+#include ModularProgram you have to create some Operator objects and
+ add them to the program.
+ All operators will be applied to each particle in the same order they've been added to the program.
+ */
+ class OSGPARTICLE_EXPORT ModularProgram: public Program {
+ public:
+ ModularProgram();
+ ModularProgram(const ModularProgram ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Node(ModularProgram);
+
+ /// Get the number of operators.
+ inline int numOperators() const;
+
+ /// Add an operator to the list.
+ inline void addOperator(Operator *o);
+
+ /// Get a pointer to an operator in the list.
+ inline Operator *getOperator(int i);
+
+ /// Get a const pointer to an operator in the list.
+ inline const Operator *getOperator(int i) const;
+
+ /// Remove an operator from the list.
+ inline void removeOperator(int i);
+
+ protected:
+ virtual ~ModularProgram() {}
+ ModularProgram &operator=(const ModularProgram &) { return *this; }
+
+ void execute(double dt);
+
+ private:
+ typedef std::vectorModularEmitter, do not call this method manually.
+ void place(Particle *P) const;
+
+ protected:
+ virtual ~MultiSegmentPlacer() {}
+ MultiSegmentPlacer &operator=(const MultiSegmentPlacer &) { return *this; }
+
+ private:
+ typedef std::pairModularProgram to perform operations on particles before they are updated.
+ To implement a new operator, derive from this class and override the operate() method.
+ You should also override the beginOperate() method to query the calling program for the reference frame
+ used, and initialize the right transformations if needed.
+ */
+ class Operator: public osg::Object {
+ public:
+ inline Operator();
+ inline Operator(const Operator ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "Operator"; }
+ virtual bool isSameKindAs(const osg::Object *obj) const { return dynamic_castModularProgram objects to perform some operations
+ on the particles. You must override it in descendant classes. Common operations
+ consist of modifying the particle's velocity vector. The dt parameter is
+ the time elapsed from last operation.
+ */
+ virtual void operate(Particle *P, double dt) = 0;
+
+ /** Do something before processing particles via the operate() method.
+ Overriding this method could be necessary to query the calling Program object
+ for the current reference frame. If the reference frame is RELATIVE_TO_PARENTS, then your
+ class should prepare itself to do all operations in local coordinates.
+ */
+ virtual void beginOperate(Program *) {}
+
+ /// Do something after all particles have been processed.
+ virtual void endOperate() {}
+
+ protected:
+ virtual ~Operator() {}
+ Operator &operator=(const Operator &) { return *this; }
+
+ private:
+ bool enabled_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline Operator::Operator()
+ : osg::Object(), enabled_(true)
+ {
+ }
+
+ inline Operator::Operator(const Operator ©, const osg::CopyOp ©op)
+ : osg::Object(copy, copyop), enabled_(copy.enabled_)
+ {
+ }
+
+ inline bool Operator::isEnabled() const
+ {
+ return enabled_;
+ }
+
+ inline void Operator::setEnabled(bool v)
+ {
+ enabled_ = v;
+ }
+
+
+}
+
+#endif
diff --git a/include/osgParticle/Particle b/include/osgParticle/Particle
new file mode 100644
index 000000000..1de466d9e
--- /dev/null
+++ b/include/osgParticle/Particle
@@ -0,0 +1,399 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_PARTICLE_
+#define OSGPARTICLE_PARTICLE_ 1
+
+#include 1 / getMass().
+ inline float getMassInv() const;
+
+ /// Get the position vector.
+ inline const osg::Vec3 &getPosition() const;
+
+ /** Get the velocity vector.
+ For built-in operators to work correctly, remember that velocity components are expressed
+ in meters per second.
+ */
+ inline const osg::Vec3 &getVelocity() const;
+
+ /// Get the previous position (the position before last update).
+ inline const osg::Vec3 &getPreviousPosition() const;
+
+ /** Kill the particle on next update
+ NOTE: after calling this function, the isAlive() method will still
+ return true until the particle is updated again.
+ */
+ inline void kill();
+
+ /// Set the life time of the particle.
+ inline void setLifeTime(double t);
+
+ /// Set the minimum and maximum values for polygon size.
+ inline void setSizeRange(const rangef &r);
+
+ /// Set the minimum and maximum values for alpha.
+ inline void setAlphaRange(const rangef &r);
+
+ /// Set the minimum and maximum values for color.
+ inline void setColorRange(const rangev4 &r);
+
+ /// Set the interpolator for computing size values.
+ inline void setSizeInterpolator(Interpolator *ri);
+
+ /// Set the interpolator for computing alpha values.
+ inline void setAlphaInterpolator(Interpolator *ai);
+
+ /// Set the interpolator for computing color values.
+ inline void setColorInterpolator(Interpolator *ci);
+
+ /** Set the physical radius of the particle.
+ For built-in operators to work correctly, lengths must be expressed in meters.
+ */
+ inline void setRadius(float r);
+
+ /** Set the mass of the particle.
+ For built-in operators to work correctly, remember that the mass is expressed in kg.
+ */
+ inline void setMass(float m);
+
+ /// Set the position vector.
+ inline void setPosition(const osg::Vec3 &p);
+
+ /** Set the velocity vector.
+ For built-in operators to work correctly, remember that velocity components are expressed
+ in meters per second.
+ */
+ inline void setVelocity(const osg::Vec3 &v);
+
+ /// Add a vector to the velocity vector.
+ inline void addVelocity(const osg::Vec3 &dv);
+
+ /// Transform position and velocity vectors by a matrix.
+ inline void transformPositionVelocity(const osg::Matrix &xform);
+
+ /** Update the particle (don't call this method manually).
+ This method is called automatically by ParticleSystem::update(); it
+ updates the graphical properties of the particle for the current time,
+ checks whether the particle is still alive, and then updates its position
+ by computing P = P + V * dt (where P is the position and V is the velocity).
+ */
+ bool update(double dt);
+
+ /// Perform some pre-rendering tasks. Called automatically by particle systems.
+ inline void beginRender();
+
+ /// Render the particle. Called automatically by particle systems.
+ void render(const osg::Matrix &modelview, float scale = 1.0f) const;
+
+ /// Perform some post-rendering tasks. Called automatically by particle systems.
+ inline void endRender();
+
+ private:
+ Shape shape_;
+
+ rangef sr_;
+ rangef ar_;
+ rangev4 cr_;
+
+ osg::ref_ptrEmitter (particle generation) and Program (particle animation).
+ This class holds some properties, like a reference frame and a reference to a ParticleSystem;
+ descendant classes should process the particles taking into account the reference frame, computing the right
+ transformations when needed.
+ */
+ class OSGPARTICLE_EXPORT ParticleProcessor: public osg::Node {
+ public:
+
+ enum ReferenceFrame {
+ RELATIVE_TO_PARENTS,
+ RELATIVE_TO_ABSOLUTE
+ };
+
+ ParticleProcessor();
+ ParticleProcessor(const ParticleProcessor ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "ParticleProcessor"; }
+ virtual bool isSameKindAs(const osg::Object *obj) { return dynamic_cast(obj) != 0; }
+ virtual void accept(osg::NodeVisitor& nv) { if (nv.validNodeMask(*this)) { nv.pushOntoNodePath(this); nv.apply(*this); nv.popFromNodePath(); } }
+
+ /// Get the reference frame.
+ inline ReferenceFrame getReferenceFrame() const;
+
+ /// Set the reference frame.
+ inline void setReferenceFrame(ReferenceFrame rf);
+
+ /// Get whether this processor is enabled or not.
+ inline bool isEnabled() const;
+
+ /// Set whether this processor is enabled or not.
+ inline void setEnabled(bool v);
+
+ /// Get a pointer to the destination particle system.
+ inline ParticleSystem *getParticleSystem();
+
+ /// Get a const pointer to the destination particle system.
+ inline const ParticleSystem *getParticleSystem() const;
+
+ /// Set the destination particle system.
+ inline void setParticleSystem(ParticleSystem *ps);
+
+ void traverse(osg::NodeVisitor &nv);
+
+ /// Get the current local-to-world transformation matrix (valid only during cull traversal).
+ inline const osg::Matrix &getLocalToWorldMatrix();
+
+ /// Get the current world-to-local transformation matrix (valid only during cull traversal).
+ inline const osg::Matrix &getWorldToLocalMatrix();
+
+ /// Transform a point from local to world coordinates (valid only during cull traversal).
+ inline osg::Vec3 transformLocalToWorld(const osg::Vec3 &P);
+
+ /// Transform a vector from local to world coordinates, discarding translation (valid only during cull traversal).
+ inline osg::Vec3 rotateLocalToWorld(const osg::Vec3 &P);
+
+ /// Transform a point from world to local coordinates (valid only during cull traversal).
+ inline osg::Vec3 transformWorldToLocal(const osg::Vec3 &P);
+
+ /// Transform a vector from world to local coordinates, discarding translation (valid only during cull traversal).
+ inline osg::Vec3 rotateWorldToLocal(const osg::Vec3 &P);
+
+ protected:
+ virtual ~ParticleProcessor() {}
+ ParticleProcessor &operator=(const ParticleProcessor &) { return *this; }
+
+ inline const bool computeBound() const;
+
+ virtual void process(double dt) = 0;
+
+ private:
+ ReferenceFrame rf_;
+ bool enabled_;
+ double t0_;
+ osg::ref_ptr ps_;
+ bool need_ltw_matrix_;
+ bool need_wtl_matrix_;
+ osg::Matrix ltw_matrix_;
+ osg::Matrix wtl_matrix_;
+ osg::NodeVisitor *current_nodevisitor_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline ParticleProcessor::ReferenceFrame ParticleProcessor::getReferenceFrame() const
+ {
+ return rf_;
+ }
+
+ inline void ParticleProcessor::setReferenceFrame(ReferenceFrame rf)
+ {
+ rf_ = rf;
+ }
+
+ inline bool ParticleProcessor::isEnabled() const
+ {
+ return enabled_;
+ }
+
+ inline void ParticleProcessor::setEnabled(bool v)
+ {
+ enabled_ = v;
+ if (enabled_) t0_ = -1;
+ }
+
+ inline ParticleSystem *ParticleProcessor::getParticleSystem()
+ {
+ return ps_.get();
+ }
+
+ inline const ParticleSystem *ParticleProcessor::getParticleSystem() const
+ {
+ return ps_.get();
+ }
+
+ inline void ParticleProcessor::setParticleSystem(ParticleSystem *ps)
+ {
+ ps_ = ps;
+ }
+
+ inline const bool ParticleProcessor::computeBound() const
+ {
+ _bsphere.init();
+ _bsphere_computed = true;
+ return true;
+ }
+
+ inline const osg::Matrix &ParticleProcessor::getLocalToWorldMatrix()
+ {
+ if (need_ltw_matrix_) {
+ ltw_matrix_ = osg::Matrix::identity();
+ current_nodevisitor_->getLocalToWorldMatrix(ltw_matrix_, this);
+ need_ltw_matrix_ = false;
+ }
+ return ltw_matrix_;
+ }
+
+ inline const osg::Matrix &ParticleProcessor::getWorldToLocalMatrix()
+ {
+ if (need_wtl_matrix_) {
+ wtl_matrix_ = osg::Matrix::identity();
+ current_nodevisitor_->getWorldToLocalMatrix(wtl_matrix_, this);
+ need_wtl_matrix_ = false;
+ }
+ return wtl_matrix_;
+ }
+
+ inline osg::Vec3 ParticleProcessor::transformLocalToWorld(const osg::Vec3 &P)
+ {
+ return getLocalToWorldMatrix().preMult(P);
+ }
+
+ inline osg::Vec3 ParticleProcessor::transformWorldToLocal(const osg::Vec3 &P)
+ {
+ return getWorldToLocalMatrix().preMult(P);
+ }
+
+ inline osg::Vec3 ParticleProcessor::rotateLocalToWorld(const osg::Vec3 &P)
+ {
+ return getLocalToWorldMatrix().preMult(P) -
+ getLocalToWorldMatrix().preMult(osg::Vec3(0, 0, 0));
+ }
+
+ inline osg::Vec3 ParticleProcessor::rotateWorldToLocal(const osg::Vec3 &P)
+ {
+ return getWorldToLocalMatrix().preMult(P) -
+ getWorldToLocalMatrix().preMult(osg::Vec3(0, 0, 0));
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/ParticleSystem b/include/osgParticle/ParticleSystem
new file mode 100644
index 000000000..a06d3a7c7
--- /dev/null
+++ b/include/osgParticle/ParticleSystem
@@ -0,0 +1,318 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_PARTICLESYSTEM_
+#define OSGPARTICLE_PARTICLESYSTEM_ 1
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace osgParticle
+{
+
+ /** The heart of this class library; its purpose is to hold a set of particles and manage particle creation, update, rendering and destruction.
+ You can add this drawable to any Geode as you usually do with other
+ Drawable classes. Each instance of ParticleSystem is a separate set of
+ particles; it provides the interface for creating particles and iterating
+ through them (see the Emitter and Program classes).
+ */
+ class OSGPARTICLE_EXPORT ParticleSystem: public osg::Drawable {
+ public:
+
+ ParticleSystem();
+ ParticleSystem(const ParticleSystem ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(ParticleSystem);
+
+ /// Get the default bounding box
+ inline const osg::BoundingBox &getDefaultBoundingBox() const;
+
+ /** Set the default bounding box.
+ The default bounding box is used when a real bounding box cannot be computed, for example
+ because no particles has been updated yet.
+ */
+ inline void setDefaultBoundingBox(const osg::BoundingBox &bbox);
+
+ /// Get the double pass rendering flag.
+ inline bool getDoublePassRendering() const;
+
+ /** Set the double pass rendering flag.
+ Double pass rendering avoids overdraw problems between particle systems
+ and other opaque objects. If you can render all the particle systems after
+ the opaque objects, then double pass is not necessary and can be turned off (best choice).
+ If you set the default attributes with setDefaultAttributes, then the particle
+ system will fall into a transparent bin.
+ */
+ inline void setDoublePassRendering(bool v);
+
+ /// Return true if the particle system is frozen.
+ inline bool isFrozen() const;
+
+ /** Set or reset the frozen state.
+ When the particle system is frozen, emitters and programs won't do anything on it.
+ */
+ inline void setFrozen(bool v);
+
+ /// Get the number of allocated particles (alive + dead).
+ inline int numParticles() const;
+
+ /// Get the number of dead particles.
+ inline int numDeadParticles() const;
+
+ /// Get a pointer to the i-th particle.
+ inline Particle *getParticle(int i);
+
+ /// Get a const pointer to the i-th particle.
+ inline const Particle *getParticle(int i) const;
+
+ /// Create a new particle from the specified template (or the default one if ptemplate is null).
+ inline virtual Particle *createParticle(const Particle *ptemplate);
+
+ /// Destroy the i-th particle.
+ inline virtual void destroyParticle(int i);
+
+ /// Get the last frame number.
+ inline int getLastFrameNumber() const;
+
+ /// Get a reference to the default particle template.
+ inline const Particle &getDefaultParticleTemplate() const;
+
+ /// Set the default particle template (particle is copied).
+ inline void setDefaultParticleTemplate(const Particle &p);
+
+ /// Get whether the particle system can freeze when culled
+ inline bool getFreezeOnCull() const;
+
+ /// Set whether the particle system can freeze when culled (default is true)
+ inline void setFreezeOnCull(bool v);
+
+ /** A useful method to set the most common StateAttribute's in one call.
+ If texturefile is empty, then texturing is turned off.
+ */
+ void setDefaultAttributes(const std::string &texturefile = "", bool emissive_particles = true, bool lighting = false);
+
+ /// (EXPERIMENTAL) Get the level of detail.
+ inline int getLevelOfDetail() const;
+
+ /** (EXPERIMENTAL) Set the level of detail. The total number of particles is divided by the detail value to
+ get the actual number of particles to be drawn. This value must be greater than zero.
+ */
+ inline void setLevelOfDetail(int v);
+
+ /// Update the particles. Don't call this directly, use a ParticleSystemUpdater instead.
+ virtual void update(double dt);
+
+ inline virtual bool getStats(osg::Statistics &stats);
+
+ protected:
+ virtual ~ParticleSystem();
+
+ ParticleSystem &operator=(const ParticleSystem &) { return *this; }
+
+ inline virtual const bool computeBound() const;
+ virtual void drawImmediateMode(osg::State &state);
+ inline void update_bounds(const osg::Vec3 &p);
+ void single_pass_render(const osg::Matrix &modelview);
+
+ private:
+ typedef std::vector Particle_vector;
+ typedef std::stack Death_stack;
+
+ Particle_vector particles_;
+ Death_stack deadparts_;
+
+ osg::BoundingBox def_bbox_;
+
+ bool doublepass_;
+ bool frozen_;
+ int display_list_id_;
+
+ osg::Vec3 bmin_;
+ osg::Vec3 bmax_;
+
+ bool reset_bounds_flag_;
+ bool bounds_computed_;
+
+ Particle def_ptemp_;
+ int last_frame_;
+ bool freeze_on_cull_;
+
+ int detail_;
+ int draw_count_;
+
+ };
+
+ // INLINE FUNCTIONS
+
+ inline bool ParticleSystem::isFrozen() const
+ {
+ return frozen_;
+ }
+
+ inline void ParticleSystem::setFrozen(bool v)
+ {
+ frozen_ = v;
+ }
+
+ inline const osg::BoundingBox &ParticleSystem::getDefaultBoundingBox() const
+ {
+ return def_bbox_;
+ }
+
+ inline void ParticleSystem::setDefaultBoundingBox(const osg::BoundingBox &bbox)
+ {
+ def_bbox_ = bbox;
+ }
+
+ inline bool ParticleSystem::getDoublePassRendering() const
+ {
+ return doublepass_;
+ }
+
+ inline void ParticleSystem::setDoublePassRendering(bool v)
+ {
+ doublepass_ = v;
+ }
+
+ inline int ParticleSystem::numParticles() const
+ {
+ return static_cast(particles_.size());
+ }
+
+ inline int ParticleSystem::numDeadParticles() const
+ {
+ return static_cast(deadparts_.size());
+ }
+
+ inline Particle *ParticleSystem::getParticle(int i)
+ {
+ return &particles_[i];
+ }
+
+ inline const Particle *ParticleSystem::getParticle(int i) const
+ {
+ return &particles_[i];
+ }
+
+ inline void ParticleSystem::destroyParticle(int i)
+ {
+ particles_[i].kill();
+ }
+
+ inline int ParticleSystem::getLastFrameNumber() const
+ {
+ return last_frame_;
+ }
+
+ inline const bool ParticleSystem::computeBound() const
+ {
+ if (!bounds_computed_) {
+ _bbox = def_bbox_;
+ } else {
+ _bbox._min = bmin_;
+ _bbox._max = bmax_;
+ }
+ _bbox_computed = true;
+ return true;
+ }
+
+ inline bool ParticleSystem::getStats(osg::Statistics &stats)
+ {
+ stats.addNumPrims(draw_count_);
+ return true;
+ }
+
+ inline void ParticleSystem::update_bounds(const osg::Vec3 &p)
+ {
+ if (reset_bounds_flag_) {
+ reset_bounds_flag_ = false;
+ bmin_ = p;
+ bmax_ = p;
+ } else {
+ if (p.x() < bmin_.x()) bmin_.x() = p.x();
+ if (p.y() < bmin_.y()) bmin_.y() = p.y();
+ if (p.z() < bmin_.z()) bmin_.z() = p.z();
+ if (p.x() > bmax_.x()) bmax_.x() = p.x();
+ if (p.y() > bmax_.y()) bmax_.y() = p.y();
+ if (p.z() > bmax_.z()) bmax_.z() = p.z();
+
+ if (!bounds_computed_)
+ bounds_computed_ = true;
+ }
+ }
+
+ inline const Particle &ParticleSystem::getDefaultParticleTemplate() const
+ {
+ return def_ptemp_;
+ }
+
+ inline void ParticleSystem::setDefaultParticleTemplate(const Particle &p)
+ {
+ def_ptemp_ = p;
+ }
+
+ inline bool ParticleSystem::getFreezeOnCull() const
+ {
+ return freeze_on_cull_;
+ }
+
+ inline void ParticleSystem::setFreezeOnCull(bool v)
+ {
+ freeze_on_cull_ = v;
+ }
+
+ inline int ParticleSystem::getLevelOfDetail() const
+ {
+ return detail_;
+ }
+
+ inline void ParticleSystem::setLevelOfDetail(int v)
+ {
+ if (v < 1) v = 1;
+ detail_ = v;
+ }
+
+ // I'm not sure this function should be inlined...
+
+ inline Particle *ParticleSystem::createParticle(const Particle *ptemplate)
+ {
+ // is there any dead particle?
+ if (!deadparts_.empty()) {
+
+ // retrieve a pointer to the last dead particle
+ Particle *P = deadparts_.top();
+
+ // create a new (alive) particle in the same place
+ *P = Particle(ptemplate? *ptemplate: def_ptemp_);
+
+ // remove the pointer from the death stack
+ deadparts_.pop();
+ return P;
+
+ } else {
+
+ // add a new particle to the vector
+ particles_.push_back(Particle(ptemplate? *ptemplate: def_ptemp_));
+ return &particles_.back();
+ }
+ }
+
+
+}
+
+#endif
diff --git a/include/osgParticle/ParticleSystemUpdater b/include/osgParticle/ParticleSystemUpdater
new file mode 100644
index 000000000..2f23341b1
--- /dev/null
+++ b/include/osgParticle/ParticleSystemUpdater
@@ -0,0 +1,128 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_PARTICLESYSTEMUPDATER_
+#define OSGPARTICLE_PARTICLESYSTEMUPDATER_ 1
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace osgParticle
+{
+
+ /** A useful node class for updating particle systems automatically.
+ When a ParticleSystemUpdater is traversed by a cull visitor, it calls the
+ update() method on the specified particle systems. You should place this updater
+ AFTER other nodes like emitters and programs.
+ */
+ class OSGPARTICLE_EXPORT ParticleSystemUpdater: public osg::Node {
+ public:
+ ParticleSystemUpdater();
+ ParticleSystemUpdater(const ParticleSystemUpdater ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Node(ParticleSystemUpdater);
+
+ /// Return the number of particle systems on the list.
+ inline int numParticleSystems() const;
+
+ /// Add a particle system to the list.
+ inline void addParticleSystem(ParticleSystem *ps);
+
+ /// Get a const particle system from the list.
+ inline const ParticleSystem *getParticleSystem(int i) const;
+
+ /// Get a particle system from the list.
+ inline ParticleSystem *getParticleSystem(int i);
+
+ /// Find a particle system.
+ inline int findParticleSystem(ParticleSystem *ps) const;
+
+ /// Remove a particle system from the list (by index).
+ inline void removeParticleSystem(int i);
+
+ /// Remove a particle system from the list (by pointer).
+ inline bool removeParticleSystem(ParticleSystem *ps);
+
+ virtual void traverse(osg::NodeVisitor &nv);
+
+ protected:
+ virtual ~ParticleSystemUpdater() {}
+ ParticleSystemUpdater &operator=(const ParticleSystemUpdater &) { return *this; }
+
+ inline virtual const bool computeBound() const;
+
+ private:
+ typedef std::vector > ParticleSystem_Vector;
+
+ ParticleSystem_Vector psv_;
+ double t0_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline const bool ParticleSystemUpdater::computeBound() const
+ {
+ _bsphere.init();
+ _bsphere_computed = true;
+ return true;
+ }
+
+ inline int ParticleSystemUpdater::numParticleSystems() const
+ {
+ return static_cast(psv_.size());
+ }
+
+ inline void ParticleSystemUpdater::addParticleSystem(ParticleSystem *ps)
+ {
+ psv_.push_back(ps);
+ }
+
+ inline const ParticleSystem *ParticleSystemUpdater::getParticleSystem(int i) const
+ {
+ return psv_[i].get();
+ }
+
+ inline ParticleSystem *ParticleSystemUpdater::getParticleSystem(int i)
+ {
+ return psv_[i].get();
+ }
+
+ inline void ParticleSystemUpdater::removeParticleSystem(int i)
+ {
+ psv_.erase(psv_.begin()+i);
+ }
+
+ inline int ParticleSystemUpdater::findParticleSystem(ParticleSystem *ps) const
+ {
+ ParticleSystem_Vector::const_iterator i;
+ int j = 0;
+ for (i=psv_.begin(); i!=psv_.end(); ++i, ++j) {
+ if (i->get() == ps) return j;
+ }
+ return -1;
+ }
+
+ inline bool ParticleSystemUpdater::removeParticleSystem(ParticleSystem *ps)
+ {
+ int i = findParticleSystem(ps);
+ if (i == -1) return false;
+ removeParticleSystem(i);
+ return true;
+ }
+
+
+}
+
+#endif
diff --git a/include/osgParticle/Placer b/include/osgParticle/Placer
new file mode 100644
index 000000000..d96dbf90e
--- /dev/null
+++ b/include/osgParticle/Placer
@@ -0,0 +1,51 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_PLACER_
+#define OSGPARTICLE_PLACER_ 1
+
+#include
+#include
+
+namespace osgParticle
+{
+
+ class Particle;
+
+ /** An abstract base class for implementing particle placers. A placer is an object which take
+ a particle as input, and places it somewhere by setting its position vector. Placer objects are
+ used by the ModularEmitter class as part of the particle emission process.
+ */
+ class Placer: public osg::Object {
+ public:
+ inline Placer();
+ inline Placer(const Placer ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "Placer"; }
+ virtual bool isSameKindAs(const osg::Object *obj) const { return dynamic_cast(obj) != 0; }
+
+ /// Place a particle. Must be implemented in descendant classes.
+ virtual void place(Particle *P) const = 0;
+
+ protected:
+ ~Placer() {}
+ Placer &operator=(const Placer &) { return *this; }
+ };
+
+ // INLINE FUNCTIONS
+
+ inline Placer::Placer()
+ : osg::Object()
+ {
+ }
+
+ inline Placer::Placer(const Placer ©, const osg::CopyOp ©op)
+ : osg::Object(copy, copyop)
+ {
+ }
+
+}
+
+#endif
diff --git a/include/osgParticle/PointPlacer b/include/osgParticle/PointPlacer
new file mode 100644
index 000000000..1143712c3
--- /dev/null
+++ b/include/osgParticle/PointPlacer
@@ -0,0 +1,61 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_POINTPLACER_
+#define OSGPARTICLE_POINTPLACER_ 1
+
+#include
+#include
+
+#include
+#include
+
+namespace osgParticle
+{
+
+ /** A point-shaped particle placer.
+ This placer class uses the center point defined in its base class CenteredPlacer
+ to place there all incoming particles.
+ */
+ class PointPlacer: public CenteredPlacer {
+ public:
+ inline PointPlacer();
+ inline PointPlacer(const PointPlacer ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(PointPlacer);
+
+ /** Place a particle.
+ This method is called automatically by ModularEmitter and should not be called
+ manually.
+ */
+ inline void place(Particle *P) const;
+
+ protected:
+ virtual ~PointPlacer() {}
+ PointPlacer &operator=(const PointPlacer &) { return *this; }
+ };
+
+ // INLINE FUNCTIONS
+
+ inline PointPlacer::PointPlacer()
+ : CenteredPlacer()
+ {
+ }
+
+ inline PointPlacer::PointPlacer(const PointPlacer ©, const osg::CopyOp ©op)
+ : CenteredPlacer(copy, copyop)
+ {
+ }
+
+ inline void PointPlacer::place(Particle *P) const
+ {
+ P->setPosition(getCenter());
+ }
+
+
+}
+
+
+#endif
diff --git a/include/osgParticle/Program b/include/osgParticle/Program
new file mode 100644
index 000000000..cfce7ff8b
--- /dev/null
+++ b/include/osgParticle/Program
@@ -0,0 +1,57 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_PROGRAM_
+#define OSGPARTICLE_PROGRAM_ 1
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace osgParticle
+{
+
+ /** An abstract ParticleProcessor descendant for modifying particles "on the fly"
+ during the cull traversal.
+ Descendants of this class must implement the execute() method, which should iterate
+ through all particles in the linked particle system and modify them somehow
+ (usually updating their velocity vector).
+ */
+ class OSGPARTICLE_EXPORT Program: public ParticleProcessor {
+ public:
+ Program();
+ Program(const Program ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "Program"; }
+ virtual bool isSameKindAs(const osg::Object *obj) { return dynamic_cast(obj) != 0; }
+ virtual void accept(osg::NodeVisitor& nv) { if (nv.validNodeMask(*this)) { nv.pushOntoNodePath(this); nv.apply(*this); nv.popFromNodePath(); } }
+
+ protected:
+ virtual ~Program() {}
+ Program &operator=(const Program &) { return *this; }
+
+ /// Implementation of ParticleProcessor::process(). Do not call this method by yourself.
+ inline void process(double dt);
+
+ /// Execute the program on the particle system. Must be overriden in descendant classes.
+ virtual void execute(double dt) = 0;
+
+ private:
+ };
+
+ // INLINE FUNCTIONS
+
+ inline void Program::process(double dt)
+ {
+ execute(dt);
+ }
+
+}
+
+#endif
diff --git a/include/osgParticle/RadialShooter b/include/osgParticle/RadialShooter
new file mode 100644
index 000000000..4bb851f40
--- /dev/null
+++ b/include/osgParticle/RadialShooter
@@ -0,0 +1,156 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_RADIALSHOOTER_
+#define OSGPARTICLE_RADIALSHOOTER_ 1
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace osgParticle
+{
+
+ /** A shooter class that shoots particles radially.
+ This shooter computes the velocity vector of incoming particles by choosing a
+ random direction and a random speed. Both direction and speed are chosen within
+ specified ranges. The direction is defined by two angles: theta, which
+ is the angle between the velocity vector and the Z axis, and phi, which is
+ the angle between the X axis and the velocity vector projected onto the X-Y plane.
+ */
+ class RadialShooter: public Shooter {
+ public:
+ inline RadialShooter();
+ inline RadialShooter(const RadialShooter ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(RadialShooter);
+
+ /// Get the range of possible values for theta angle.
+ inline const rangef &getThetaRange() const;
+
+ /// Set the range of possible values for theta angle.
+ inline void setThetaRange(const rangef &r);
+
+ /// Set the range of possible values for theta angle.
+ inline void setThetaRange(float r1, float r2);
+
+ /// Get the range of possible values for phi angle.
+ inline const rangef &getPhiRange() const;
+
+ /// Set the range of possible values for phi angle.
+ inline void setPhiRange(const rangef &r);
+
+ /// Set the range of possible values for phi angle.
+ inline void setPhiRange(float r1, float r2);
+
+ /// Get the range of possible values for initial speed of particles.
+ inline const rangef &getInitialSpeedRange() const;
+
+ /// Set the range of possible values for initial speed of particles.
+ inline void setInitialSpeedRange(const rangef &r);
+
+ /// Set the range of possible values for initial speed of particles.
+ inline void setInitialSpeedRange(float r1, float r2);
+
+ /// Shoot a particle. Do not call this method manually.
+ inline void shoot(Particle *P) const;
+
+ protected:
+ virtual ~RadialShooter() {}
+ RadialShooter &operator=(const RadialShooter &) { return *this; }
+
+ private:
+ rangef theta_range_;
+ rangef phi_range_;
+ rangef speed_range_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline RadialShooter::RadialShooter()
+ : Shooter(),
+ theta_range_(0, 0.5f*osg::PI_4),
+ phi_range_(0, 2*osg::PI),
+ speed_range_(10, 10)
+ {
+ }
+
+ inline RadialShooter::RadialShooter(const RadialShooter ©, const osg::CopyOp ©op)
+ : Shooter(copy, copyop),
+ theta_range_(copy.theta_range_),
+ phi_range_(copy.phi_range_),
+ speed_range_(copy.speed_range_)
+ {
+ }
+
+ inline const rangef &RadialShooter::getThetaRange() const
+ {
+ return theta_range_;
+ }
+
+ inline const rangef &RadialShooter::getPhiRange() const
+ {
+ return phi_range_;
+ }
+
+ inline const rangef &RadialShooter::getInitialSpeedRange() const
+ {
+ return speed_range_;
+ }
+
+ inline void RadialShooter::setThetaRange(const rangef &r)
+ {
+ theta_range_ = r;
+ }
+
+ inline void RadialShooter::setThetaRange(float r1, float r2)
+ {
+ theta_range_.min = r1;
+ theta_range_.max = r2;
+ }
+
+ inline void RadialShooter::setPhiRange(const rangef &r)
+ {
+ phi_range_ = r;
+ }
+
+ inline void RadialShooter::setPhiRange(float r1, float r2)
+ {
+ phi_range_.min = r1;
+ phi_range_.max = r2;
+ }
+
+ inline void RadialShooter::setInitialSpeedRange(const rangef &r)
+ {
+ speed_range_ = r;
+ }
+
+ inline void RadialShooter::setInitialSpeedRange(float r1, float r2)
+ {
+ speed_range_.min = r1;
+ speed_range_.max = r2;
+ }
+
+ inline void RadialShooter::shoot(Particle *P) const
+ {
+ float theta = theta_range_.get_random();
+ float phi = phi_range_.get_random();
+ float speed = speed_range_.get_random();
+
+ P->setVelocity(osg::Vec3(
+ speed * sinf(theta) * cosf(phi),
+ speed * sinf(theta) * sinf(phi),
+ speed * cosf(theta)
+ ));
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/RandomRateCounter b/include/osgParticle/RandomRateCounter
new file mode 100644
index 000000000..937017420
--- /dev/null
+++ b/include/osgParticle/RandomRateCounter
@@ -0,0 +1,57 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_RANDOMRATECOUNTER_
+#define OSGPARTICLE_RANDOMRATECOUNTER_ 1
+
+#include
+
+#include
+#include
+
+namespace osgParticle
+{
+
+ class RandomRateCounter: public VariableRateCounter {
+ public:
+ inline RandomRateCounter();
+ inline RandomRateCounter(const RandomRateCounter ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(RandomRateCounter);
+
+ /// Return the number of particles to be created in this frame
+ inline int numParticlesToCreate(double dt) const;
+
+ protected:
+ virtual ~RandomRateCounter() {}
+
+ private:
+ mutable float np_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline RandomRateCounter::RandomRateCounter()
+ : VariableRateCounter(), np_(0)
+ {
+ }
+
+ inline RandomRateCounter::RandomRateCounter(const RandomRateCounter ©, const osg::CopyOp ©op)
+ : VariableRateCounter(copy, copyop), np_(copy.np_)
+ {
+ }
+
+ inline int RandomRateCounter::numParticlesToCreate(double dt) const
+ {
+ np_ += dt * getRateRange().get_random();
+ int n = static_cast(np_);
+ np_ -= n;
+ return n;
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/SectorPlacer b/include/osgParticle/SectorPlacer
new file mode 100644
index 000000000..225f09dac
--- /dev/null
+++ b/include/osgParticle/SectorPlacer
@@ -0,0 +1,124 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_SECTORPLACER_
+#define OSGPARTICLE_SECTORPLACER_ 1
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace osgParticle
+{
+
+ /** A sector-shaped particle placer.
+ This placer sets the initial position of incoming particle by choosing a random position
+ within a circular sector; this sector is defined by three parameters: a center point,
+ which is inherited directly from osgParticle::CenteredPlacer, a range of values
+ for radius, and a range of values for the central angle (sometimes called phi).
+ */
+ class SectorPlacer: public CenteredPlacer {
+ public:
+ inline SectorPlacer();
+ inline SectorPlacer(const SectorPlacer ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ /// Get the range of possible values for radius.
+ inline const rangef &getRadiusRange() const;
+
+ /// Set the range of possible values for radius.
+ inline void setRadiusRange(const rangef &r);
+
+ /// Set the range of possible values for radius.
+ inline void setRadiusRange(float r1, float r2);
+
+ /// Get the range of possible values for the central angle.
+ inline const rangef &getPhiRange() const;
+
+ /// Set the range of possible values for the central angle.
+ inline void setPhiRange(const rangef &r);
+
+ /// Set the range of possible values for the central angle.
+ inline void setPhiRange(float r1, float r2);
+
+ META_Object(SectorPlacer);
+
+ /// Place a particle. Do not call it manually.
+ inline void place(Particle *P) const;
+
+ protected:
+ virtual ~SectorPlacer() {}
+ SectorPlacer &operator=(const SectorPlacer &) { return *this; }
+
+ private:
+ rangef rad_range_;
+ rangef phi_range_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline SectorPlacer::SectorPlacer()
+ : CenteredPlacer(), rad_range_(0, 1), phi_range_(0, osg::PI*2)
+ {
+ }
+
+ inline SectorPlacer::SectorPlacer(const SectorPlacer ©, const osg::CopyOp ©op)
+ : CenteredPlacer(copy, copyop), rad_range_(copy.rad_range_), phi_range_(copy.phi_range_)
+ {
+ }
+
+ inline const rangef &SectorPlacer::getRadiusRange() const
+ {
+ return rad_range_;
+ }
+
+ inline const rangef &SectorPlacer::getPhiRange() const
+ {
+ return phi_range_;
+ }
+
+ inline void SectorPlacer::setRadiusRange(const rangef &r)
+ {
+ rad_range_ = r;
+ }
+
+ inline void SectorPlacer::setRadiusRange(float r1, float r2)
+ {
+ rad_range_.min = r1;
+ rad_range_.max = r2;
+ }
+
+ inline void SectorPlacer::setPhiRange(const rangef &r)
+ {
+ phi_range_ = r;
+ }
+
+ inline void SectorPlacer::setPhiRange(float r1, float r2)
+ {
+ phi_range_.min = r1;
+ phi_range_.max = r2;
+ }
+
+ inline void SectorPlacer::place(Particle *P) const
+ {
+ float rad = rad_range_.get_random();
+ float phi = phi_range_.get_random();
+
+ osg::Vec3 pos(
+ getCenter().x() + rad * cosf(phi),
+ getCenter().y() + rad * sinf(phi),
+ getCenter().z());
+
+ P->setPosition(pos);
+ }
+
+
+}
+
+#endif
diff --git a/include/osgParticle/SegmentPlacer b/include/osgParticle/SegmentPlacer
new file mode 100644
index 000000000..381bcd1c8
--- /dev/null
+++ b/include/osgParticle/SegmentPlacer
@@ -0,0 +1,118 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_SEGMENTPLACER_
+#define OSGPARTICLE_SEGMENTPLACER_ 1
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace osgParticle {
+
+ /** A segment-shaped particle placer.
+ To use this placer you have to define a segment, by setting its two vertices (A and B);
+ when an emitter requests a SegmentPlacer to place a particle, the position is chosen randomly
+ within that segment.
+ */
+ class SegmentPlacer: public Placer {
+ public:
+ inline SegmentPlacer();
+ inline SegmentPlacer(const SegmentPlacer ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ META_Object(SegmentPlacer);
+
+ /// get vertex A.
+ inline const osg::Vec3 &getVertexA() const;
+
+ /// Set vertex A of the segment as a vector.
+ inline void setVertexA(const osg::Vec3 &v);
+
+ /// Set vertex A of the segment as three floats.
+ inline void setVertexA(float x, float y, float z);
+
+ /// get vertex B.
+ inline const osg::Vec3 &getVertexB() const;
+
+ /// Set vertex B of the segment as a vector.
+ inline void setVertexB(const osg::Vec3 &v);
+
+ /// Set vertex B of the segment as three floats.
+ inline void setVertexB(float x, float y, float z);
+
+ /// Set both vertices.
+ inline void setSegment(const osg::Vec3 &A, const osg::Vec3 &B);
+
+ /// Place a particle. This method is called by ModularEmitter, do not call it manually.
+ inline void place(Particle *P) const;
+
+ protected:
+ virtual ~SegmentPlacer() {}
+ SegmentPlacer &operator=(const SegmentPlacer &) { return *this; }
+
+ private:
+ osg::Vec3 A_;
+ osg::Vec3 B_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline SegmentPlacer::SegmentPlacer()
+ : Placer(), A_(-1, 0, 0), B_(1, 0, 0)
+ {
+ }
+
+ inline SegmentPlacer::SegmentPlacer(const SegmentPlacer ©, const osg::CopyOp ©op)
+ : Placer(copy, copyop), A_(copy.A_), B_(copy.B_)
+ {
+ }
+
+ inline const osg::Vec3 &SegmentPlacer::getVertexA() const
+ {
+ return A_;
+ }
+
+ inline const osg::Vec3 &SegmentPlacer::getVertexB() const
+ {
+ return B_;
+ }
+
+ inline void SegmentPlacer::setSegment(const osg::Vec3 &A, const osg::Vec3 &B)
+ {
+ A_ = A;
+ B_ = B;
+ }
+
+ inline void SegmentPlacer::place(Particle *P) const
+ {
+ P->setPosition(rangev3(A_, B_).get_random());
+ }
+
+ inline void SegmentPlacer::setVertexA(const osg::Vec3 &v)
+ {
+ A_ = v;
+ }
+
+ inline void SegmentPlacer::setVertexA(float x, float y, float z)
+ {
+ A_.set(x, y, z);
+ }
+
+ inline void SegmentPlacer::setVertexB(const osg::Vec3 &v)
+ {
+ B_ = v;
+ }
+
+ inline void SegmentPlacer::setVertexB(float x, float y, float z)
+ {
+ B_.set(x, y, z);
+ }
+
+}
+
+#endif
diff --git a/include/osgParticle/Shooter b/include/osgParticle/Shooter
new file mode 100644
index 000000000..b1ee010e2
--- /dev/null
+++ b/include/osgParticle/Shooter
@@ -0,0 +1,53 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_SHOOTER_
+#define OSGPARTICLE_SHOOTER_ 1
+
+#include
+#include
+
+namespace osgParticle
+{
+
+ class Particle;
+
+ /** An abstract base class used by ModularEmitter to "shoot" the particles after they have been placed.
+ Descendants of this class must override the shoot() method.
+ */
+ class Shooter: public osg::Object {
+ public:
+ inline Shooter();
+ inline Shooter(const Shooter ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "Shooter"; }
+ virtual bool isSameKindAs(const osg::Object *obj) const { return dynamic_cast(obj) != 0; }
+
+ /** Shoot a particle. Must be overriden by descendants.
+ This method should only set the velocity vector of particle P, leaving other
+ attributes unchanged.
+ */
+ virtual void shoot(Particle *P) const = 0;
+
+ protected:
+ virtual ~Shooter() {}
+ Shooter &operator=(const Shooter &) { return *this; }
+ };
+
+ // INLINE FUNCTIONS
+
+ inline Shooter::Shooter()
+ : osg::Object()
+ {
+ }
+
+ inline Shooter::Shooter(const Shooter ©, const osg::CopyOp ©op)
+ : osg::Object(copy, copyop)
+ {
+ }
+
+}
+
+#endif
diff --git a/include/osgParticle/VariableRateCounter b/include/osgParticle/VariableRateCounter
new file mode 100644
index 000000000..727b7ba0e
--- /dev/null
+++ b/include/osgParticle/VariableRateCounter
@@ -0,0 +1,67 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_VARIABLERATECOUNTER_
+#define OSGPARTICLE_VARIABLERATECOUNTER_ 1
+
+#include
+#include
+
+#include
+#include
+
+namespace osgParticle
+{
+
+ class VariableRateCounter: public Counter {
+ public:
+ inline VariableRateCounter();
+ inline VariableRateCounter(const VariableRateCounter ©, const osg::CopyOp ©op = osg::CopyOp::SHALLOW_COPY);
+
+ virtual const char *className() const { return "VariableRateCounter"; }
+ virtual bool isSameKindAs(const osg::Object *obj) const { return dynamic_cast(obj) != 0; }
+
+ inline const rangef &getRateRange() const;
+ inline void setRateRange(const rangef &r);
+ inline void setRateRange(float minrange, float maxrange);
+
+ protected:
+ virtual ~VariableRateCounter() {}
+
+ private:
+ rangef rate_range_;
+ };
+
+ // INLINE FUNCTIONS
+
+ inline VariableRateCounter::VariableRateCounter()
+ : Counter(), rate_range_(1, 1)
+ {
+ }
+
+ inline VariableRateCounter::VariableRateCounter(const VariableRateCounter ©, const osg::CopyOp ©op)
+ : Counter(copy, copyop), rate_range_(copy.rate_range_)
+ {
+ }
+
+ inline const rangef &VariableRateCounter::getRateRange() const
+ {
+ return rate_range_;
+ }
+
+ inline void VariableRateCounter::setRateRange(const rangef &r)
+ {
+ rate_range_ = r;
+ }
+
+ inline void VariableRateCounter::setRateRange(float minrange, float maxrange)
+ {
+ rate_range_.set(minrange, maxrange);
+ }
+
+}
+
+
+#endif
diff --git a/include/osgParticle/Version b/include/osgParticle/Version
new file mode 100644
index 000000000..5ff598bc6
--- /dev/null
+++ b/include/osgParticle/Version
@@ -0,0 +1,19 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_VERSION_
+#define OSGPARTICLE_VERSION_ 1
+
+#include
+
+extern "C" {
+
+OSGPARTICLE_EXPORT const char* osgParticleGetVersion();
+OSGPARTICLE_EXPORT const char* osgParticleGetLibraryName();
+
+}
+
+#endif
+
diff --git a/include/osgParticle/range b/include/osgParticle/range
new file mode 100644
index 000000000..d3bc93a4c
--- /dev/null
+++ b/include/osgParticle/range
@@ -0,0 +1,65 @@
+//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
+//Distributed under the terms of the GNU Library General Public License (LGPL)
+//as published by the Free Software Foundation.
+//osgParticle - Copyright (C) 2002 Marco Jez
+
+#ifndef OSGPARTICLE_RANGE_
+#define OSGPARTICLE_RANGE_ 1
+
+#include
+
+#include
+#include
+#include
+
+namespace osgParticle
+{
+
+ /**
+ A simple struct template useful to store ranges of values as min/max pairs.
+ This struct template helps storing min/max ranges for values of any kind; class T_ is
+ the type of values to be stored, and it must support operations T_ + T_, T_ - T_,
+ and T_ * float, otherwise the get_random() method will not compile.
+ This struct could be extended to customize the random number generator (now it uses only
+ std::rand()).
+ */
+ template struct range {
+
+ /// Lower bound.
+ T_ min;
+
+ /// Higher bound.
+ T_ max;
+
+ /// Construct the object by calling default constructors for min and max.
+ range() : min(T_()), max(T_()) {}
+
+ /// Construct and initialize min and max directly.
+ range(const T_ &mn, const T_ &mx) : min(mn), max(mx) {}
+
+ /// Set min and max.
+ void set(const T_ &mn, const T_ &mx) { min = mn; max = mx; }
+
+ /// Get a random value between min and max.
+ T_ get_random() const
+ {
+ return min + (max - min) * std::rand() / RAND_MAX;
+ }
+
+ };
+
+ /// Range of floats.
+ typedef range rangef;
+
+ /// Range of osg::Vec2s.
+ typedef range rangev2;
+
+ /// Range of osg::Vec3s.
+ typedef range rangev3;
+
+ /// Range of osg::Vec4s.
+ typedef range rangev4;
+
+}
+
+#endif
diff --git a/src/Demos/osgparticle/Makefile b/src/Demos/osgparticle/Makefile
new file mode 100644
index 000000000..648e825cd
--- /dev/null
+++ b/src/Demos/osgparticle/Makefile
@@ -0,0 +1,16 @@
+TOPDIR = ../../..
+include $(TOPDIR)/Make/makedefs
+
+CXXFILES =\
+ osgparticle.cpp\
+
+LIBS += $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) -losgParticle
+
+INSTFILES = \
+ $(CXXFILES)\
+ Makefile.inst=Makefile
+
+EXEC = osgparticle
+
+include $(TOPDIR)/Make/makerules
+
diff --git a/src/Demos/osgparticle/Makefile.inst b/src/Demos/osgparticle/Makefile.inst
new file mode 100644
index 000000000..066678e60
--- /dev/null
+++ b/src/Demos/osgparticle/Makefile.inst
@@ -0,0 +1,13 @@
+TOPDIR = ../..
+include $(TOPDIR)/Make/makedefs
+
+CXXFILES =\
+ osgparticle.cpp\
+
+LIBS += $(OSG_LIBS) $(GLUT_LIB) $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) -losgParticle
+
+EXEC = osgparticle
+
+
+include $(TOPDIR)/Make/makerules
+
diff --git a/src/Demos/osgparticle/osgparticle.cpp b/src/Demos/osgparticle/osgparticle.cpp
new file mode 100644
index 000000000..79194b794
--- /dev/null
+++ b/src/Demos/osgparticle/osgparticle.cpp
@@ -0,0 +1,120 @@
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+// ----------------------------------------------------------------------------------
+// These lines are necessary under Windows because if we don't instantiate at least
+// one object of osgParticle, the library will not be linked to the exe even if we
+// add it to the dependancies list, leading to failure when importing .osg files.
+
+#ifdef WIN32
+
+#include
+osgParticle::Particle dummy_Particle__;
+
+#endif
+
+// ----------------------------------------------------------------------------------
+
+void write_usage(std::ostream& out,const std::string& name)
+{
+ out << std::endl;
+ out <<"usage:"<< std::endl;
+ out <<" "< commandLine;
+ for(int i=1;i
+#include
+
+#include
+
+osgParticle::Emitter::Emitter()
+: ParticleProcessor(),
+ usedeftemp_(true)
+{
+}
+
+osgParticle::Emitter::Emitter(const Emitter ©, const osg::CopyOp ©op)
+: ParticleProcessor(copy, copyop),
+ usedeftemp_(copy.usedeftemp_),
+ ptemp_(copy.ptemp_)
+{
+}
diff --git a/src/osgParticle/FluidFrictionOperator.cpp b/src/osgParticle/FluidFrictionOperator.cpp
new file mode 100644
index 000000000..6ac4309d9
--- /dev/null
+++ b/src/osgParticle/FluidFrictionOperator.cpp
@@ -0,0 +1,38 @@
+#include
+#include
+#include
+#include
+#include
+
+osgParticle::FluidFrictionOperator::FluidFrictionOperator()
+: Operator(), ovr_rad_(0)
+{
+ setFluidToAir();
+}
+
+osgParticle::FluidFrictionOperator::FluidFrictionOperator(const FluidFrictionOperator ©, const osg::CopyOp ©op)
+: Operator(copy, copyop),
+ A_(copy.A_),
+ B_(copy.B_),
+ density_(copy.density_),
+ viscosity_(copy.viscosity_),
+ ovr_rad_(copy.ovr_rad_)
+{
+}
+
+void osgParticle::FluidFrictionOperator::operate(Particle *P, double dt)
+{
+ float r = (ovr_rad_ > 0)? ovr_rad_ : P->getRadius();
+ osg::Vec3 v = P->getVelocity();
+
+ float vm = v.normalize();
+ float R = A_ * r * vm + B_ * r * r * vm * vm;
+
+ osg::Vec3 Fr(-R * v.x(), -R * v.y(), -R * v.z());
+
+ if (current_program_->getReferenceFrame() == ModularProgram::RELATIVE_TO_PARENTS) {
+ Fr = current_program_->rotateLocalToWorld(Fr);
+ }
+
+ P->addVelocity(Fr * (P->getMassInv() * dt));
+}
diff --git a/src/osgParticle/IO_AccelOperator.cpp b/src/osgParticle/IO_AccelOperator.cpp
new file mode 100644
index 000000000..dbde4c3de
--- /dev/null
+++ b/src/osgParticle/IO_AccelOperator.cpp
@@ -0,0 +1,48 @@
+
+#include
+
+#include
+#include
+#include
+
+#include