1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
13//osgParticle - Copyright (C) 2002 Marco Jez
15#ifndef OSGPARTICLE_PARTICLESYSTEM
16#define OSGPARTICLE_PARTICLESYSTEM 1
18#include <osgParticle/Export>
19#include <osgParticle/Particle>
27#include <osg/Drawable>
31#include <osg/BoundingBox>
33// 9th Febrary 2009, disabled the use of ReadWriteMutex as it looks like this
34// is introducing threading problems due to threading problems in OpenThreads::ReadWriteMutex.
35// #define OSGPARTICLE_USE_ReadWriteMutex
37#ifdef OSGPARTICLE_USE_ReadWriteMutex
38 #include <OpenThreads/ReadWriteMutex>
40 #include <OpenThreads/Mutex>
41 #include <OpenThreads/ScopedLock>
48 /** The heart of this class library; its purpose is to hold a set of particles and manage particle creation, update, rendering and destruction.
49 * You can add this drawable to any Geode as you usually do with other
50 * Drawable classes. Each instance of ParticleSystem is a separate set of
51 * particles; it provides the interface for creating particles and iterating
52 * through them (see the Emitter and Program classes).
54 class OSGPARTICLE_EXPORT ParticleSystem: public osg::Drawable {
63 ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
65 META_Object(osgParticle, ParticleSystem);
67 /// Get the alignment type of particles.
68 inline Alignment getParticleAlignment() const;
70 /// Set the alignment type of particles.
71 inline void setParticleAlignment(Alignment a);
73 /// Get the X-axis alignment vector.
74 inline const osg::Vec3& getAlignVectorX() const;
76 /// Set the X-axis alignment vector.
77 inline void setAlignVectorX(const osg::Vec3& v);
79 /// Get the Y-axis alignment vector.
80 inline const osg::Vec3& getAlignVectorY() const;
82 /// Set the Y-axis alignment vector.
83 inline void setAlignVectorY(const osg::Vec3& v);
85 /// Set the alignment vectors.
86 inline void setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y);
90 enum ParticleScaleReferenceFrame
96 /** Set whether the particles should be scaled relative to world coordaintes or local coordinates.*/
97 void setParticleScaleReferenceFrame(ParticleScaleReferenceFrame rf) { _particleScaleReferenceFrame = rf; }
99 /** Get whether the particles should be scaled relative to world coordaintes or local coordinates.*/
100 ParticleScaleReferenceFrame getParticleScaleReferenceFrame() const { return _particleScaleReferenceFrame; }
104 /// Get the default bounding box
105 inline const osg::BoundingBox& getDefaultBoundingBox() const;
107 /** Set the default bounding box.
108 The default bounding box is used when a real bounding box cannot be computed, for example
109 because no particles has been updated yet.
111 inline void setDefaultBoundingBox(const osg::BoundingBox& bbox);
113 /// Return true if we use vertex arrays for rendering particles.
114 bool getUseVertexArray() const { return _useVertexArray; }
116 /** Set to use vertex arrays for rendering particles.
117 Lots of variables will be omitted: particles' shape, alive or not, visibility distance, and so on,
118 so the rendering result is not as good as we wish (although it's fast than using glBegin/glEnd).
119 We had better use this for GLSL shaders, in which particle parameters will be kept as uniforms.
120 This method is called automatically by <CODE>setDefaultAttributesUsingShaders()</CODE>.
122 void setUseVertexArray(bool v) { _useVertexArray = v; }
124 /// Return true if shaders are required.
125 bool getUseShaders() const { return _useShaders; }
127 /** Set to use GLSL shaders for rendering particles.
128 Particles' parameters will be used as shader attribute arrays, and necessary variables, including
129 the visibility distance, texture, etc, will be used and updated as uniforms.
131 void setUseShaders(bool v) { _useShaders = v; _dirty_uniforms = true; }
133 /// Get the double pass rendering flag.
134 inline bool getDoublePassRendering() const;
136 /** Set the double pass rendering flag.
137 Double pass rendering avoids overdraw problems between particle systems
138 and other opaque objects. If you can render all the particle systems after
139 the opaque objects, then double pass is not necessary and can be turned off (best choice).
140 If you set the default attributes with setDefaultAttributes, then the particle
141 system will fall into a transparent bin.
143 inline void setDoublePassRendering(bool v);
145 /// Return true if the particle system is frozen.
146 bool getFrozen() const { return _frozen; }
147 inline bool isFrozen() const;
149 /** Set or reset the <I>frozen</I> state.
150 When the particle system is frozen, emitters and programs won't do anything on it.
152 inline void setFrozen(bool v);
154 /// Get the number of allocated particles (alive + dead).
155 inline int numParticles() const;
157 /// Get the number of dead particles.
158 inline int numDeadParticles() const;
160 /// Get whether all particles are dead
161 inline bool areAllParticlesDead() const { return numDeadParticles()==numParticles(); }
163 /// Get a pointer to the i-th particle.
164 inline Particle* getParticle(int i);
166 /// Get a const pointer to the i-th particle.
167 inline const Particle* getParticle(int i) const;
169 /// Create a new particle from the specified template (or the default one if <CODE>ptemplate</CODE> is null).
170 virtual Particle* createParticle(const Particle* ptemplate);
172 /// Destroy the i-th particle.
173 inline virtual void destroyParticle(int i);
175 /// Reuse the i-th particle.
176 inline virtual void reuseParticle(int i) { _deadparts.push(&(_particles[i])); }
178 /// Get the last frame number.
179 inline unsigned int getLastFrameNumber() const;
181 /// Get the unique delta time for emitters and updaters to use
182 inline double& getDeltaTime( double currentTime );
184 /// Get a reference to the default particle template.
185 inline Particle& getDefaultParticleTemplate();
187 /// Get a const reference to the default particle template.
188 inline const Particle& getDefaultParticleTemplate() const;
190 /// Set the default particle template (particle is copied).
191 inline void setDefaultParticleTemplate(const Particle& p);
193 /// Get whether the particle system can freeze when culled
194 inline bool getFreezeOnCull() const;
196 /// Set whether the particle system can freeze when culled (default is true)
197 inline void setFreezeOnCull(bool v);
199 /** A useful method to set the most common <CODE>StateAttribute</CODE>'s in one call.
200 If <CODE>texturefile</CODE> is empty, then texturing is turned off.
202 void setDefaultAttributes(const std::string& texturefile = "", bool emissive_particles = true, bool lighting = false, int texture_unit = 0);
204 /** A useful method to set the most common <CODE>StateAttribute</CODE> and use GLSL shaders to draw particles.
205 At present, when enabling shaders in the particle system, user-defined shapes will not be usable.
206 If <CODE>texturefile</CODE> is empty, then texturing is turned off.
208 void setDefaultAttributesUsingShaders(const std::string& texturefile = "", bool emissive_particles = true, int texture_unit = 0);
210 /// (<B>EXPERIMENTAL</B>) Get the level of detail.
211 inline int getLevelOfDetail() const;
213 /** (<B>EXPERIMENTAL</B>) Set the level of detail. The total number of particles is divided by the detail value to
214 get the actual number of particles to be drawn. This value must be greater than zero.
216 inline void setLevelOfDetail(int v);
225 /// Get the sort mode.
226 inline SortMode getSortMode() const;
228 /** Set the sort mode. It will force resorting the particle list by the Z direction of the view coordinates.
229 This can be used for the purpose of transparent rendering or <CODE>setVisibilityDistance()</CODE>.
231 inline void setSortMode(SortMode mode);
233 /// Get the visibility distance.
234 inline double getVisibilityDistance() const;
236 /** Set the visibility distance which allows the particles to be rendered only when depth is inside the distance.
237 When using shaders, it can work well directly; otherwise the sort mode should also be set to pre-compute depth.
239 inline void setVisibilityDistance(double distance);
241 /// Update the particles. Don't call this directly, use a <CODE>ParticleSystemUpdater</CODE> instead.
242 virtual void update(double dt, osg::NodeVisitor& nv);
244 virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
246 virtual osg::BoundingBox computeBoundingBox() const;
248#ifdef OSGPARTICLE_USE_ReadWriteMutex
249 typedef OpenThreads::ReadWriteMutex ReadWriterMutex;
250 typedef OpenThreads::ScopedReadLock ScopedReadLock;
251 typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
253 typedef OpenThreads::Mutex ReadWriterMutex;
254 typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedReadLock;
255 typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedWriteLock;
258 ReadWriterMutex* getReadWriteMutex() const { return &_readWriteMutex; }
260 /** Resize any per context GLObject buffers to specified size. */
261 virtual void resizeGLObjectBuffers(unsigned int maxSize);
263 /** If State is non-zero, this function releases OpenGL objects for
264 * the specified graphics context. Otherwise, releases OpenGL objects
265 * for all graphics contexts. */
266 virtual void releaseGLObjects(osg::State* state=0) const;
268 virtual osg::VertexArrayState* createVertexArrayStateImplementation(osg::RenderInfo& renderInfo) const;
270 void adjustEstimatedMaxNumOfParticles(int delta) { _estimatedMaxNumOfParticles += delta; }
272 void setEstimatedMaxNumOfParticles(int num) { _estimatedMaxNumOfParticles = num; }
273 int getEstimatedMaxNumOfParticles() const { return _estimatedMaxNumOfParticles; }
277 virtual ~ParticleSystem();
279 ParticleSystem& operator=(const ParticleSystem&) { return *this; }
281 inline void update_bounds(const osg::Vec3& p, float r);
283 typedef std::vector<Particle> Particle_vector;
284 typedef std::stack<Particle*> Death_stack;
286 Particle_vector _particles;
287 Death_stack _deadparts;
289 osg::BoundingBox _def_bbox;
291 Alignment _alignment;
292 osg::Vec3 _align_X_axis;
293 osg::Vec3 _align_Y_axis;
294 ParticleScaleReferenceFrame _particleScaleReferenceFrame;
296 bool _useVertexArray;
298 bool _dirty_uniforms;
306 bool _reset_bounds_flag;
307 bool _bounds_computed;
310 mutable unsigned int _last_frame;
311 mutable bool _dirty_dt;
312 bool _freeze_on_cull;
319 double _visibilityDistance;
321 mutable ReadWriterMutex _readWriteMutex;
323 int _estimatedMaxNumOfParticles;
325 struct OSGPARTICLE_EXPORT ArrayData
332 void reserve(unsigned int numVertices);
333 void resize(unsigned int numVertices);
334 void resizeGLObjectBuffers(unsigned int maxSize);
335 void releaseGLObjects(osg::State* state);
340 void dispatchArrays(osg::State& state);
341 void dispatchPrimitives();
343 osg::ref_ptr<osg::BufferObject> vertexBufferObject;
344 osg::ref_ptr<osg::Vec3Array> vertices;
345 osg::ref_ptr<osg::Vec3Array> normals;
346 osg::ref_ptr<osg::Vec4Array> colors;
347 osg::ref_ptr<osg::Vec2Array> texcoords2;
348 osg::ref_ptr<osg::Vec3Array> texcoords3;
350 typedef std::pair<GLenum, unsigned int> ModeCount;
351 typedef std::vector<ModeCount> Primitives;
352 Primitives primitives;
355 typedef osg::buffered_object< ArrayData > BufferedArrayData;
356 mutable BufferedArrayData _bufferedArrayData;
361 inline ParticleSystem::Alignment ParticleSystem::getParticleAlignment() const
366 inline void ParticleSystem::setParticleAlignment(Alignment a)
371 inline const osg::Vec3& ParticleSystem::getAlignVectorX() const
373 return _align_X_axis;
376 inline void ParticleSystem::setAlignVectorX(const osg::Vec3& v)
381 inline const osg::Vec3& ParticleSystem::getAlignVectorY() const
383 return _align_Y_axis;
386 inline void ParticleSystem::setAlignVectorY(const osg::Vec3& v)
391 inline void ParticleSystem::setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y)
397 inline bool ParticleSystem::isFrozen() const
402 inline void ParticleSystem::setFrozen(bool v)
407 inline const osg::BoundingBox& ParticleSystem::getDefaultBoundingBox() const
412 inline void ParticleSystem::setDefaultBoundingBox(const osg::BoundingBox& bbox)
417 inline bool ParticleSystem::getDoublePassRendering() const
422 inline void ParticleSystem::setDoublePassRendering(bool v)
427 inline int ParticleSystem::numParticles() const
429 return static_cast<int>(_particles.size());
432 inline int ParticleSystem::numDeadParticles() const
434 return static_cast<int>(_deadparts.size());
437 inline Particle* ParticleSystem::getParticle(int i)
439 return &_particles[i];
442 inline const Particle* ParticleSystem::getParticle(int i) const
444 return &_particles[i];
447 inline void ParticleSystem::destroyParticle(int i)
449 _particles[i].kill();
452 inline unsigned int ParticleSystem::getLastFrameNumber() const
457 inline double& ParticleSystem::getDeltaTime( double currentTime )
461 _dt = currentTime - _t0;
462 if ( _dt<0.0 ) _dt = 0.0;
470 inline void ParticleSystem::update_bounds(const osg::Vec3& p, float r)
472 if (_reset_bounds_flag) {
473 _reset_bounds_flag = false;
474 _bmin = p - osg::Vec3(r,r,r);
475 _bmax = p + osg::Vec3(r,r,r);
477 if (p.x() - r < _bmin.x()) _bmin.x() = p.x() - r;
478 if (p.y() - r < _bmin.y()) _bmin.y() = p.y() - r;
479 if (p.z() - r < _bmin.z()) _bmin.z() = p.z() - r;
480 if (p.x() + r > _bmax.x()) _bmax.x() = p.x() + r;
481 if (p.y() + r > _bmax.y()) _bmax.y() = p.y() + r;
482 if (p.z() + r > _bmax.z()) _bmax.z() = p.z() + r;
484 if (!_bounds_computed)
485 _bounds_computed = true;
488 inline Particle& ParticleSystem::getDefaultParticleTemplate()
493 inline const Particle& ParticleSystem::getDefaultParticleTemplate() const
498 inline void ParticleSystem::setDefaultParticleTemplate(const Particle& p)
503 inline bool ParticleSystem::getFreezeOnCull() const
505 return _freeze_on_cull;
508 inline void ParticleSystem::setFreezeOnCull(bool v)
513 inline int ParticleSystem::getLevelOfDetail() const
518 inline void ParticleSystem::setLevelOfDetail(int v)
524 inline ParticleSystem::SortMode ParticleSystem::getSortMode() const
529 inline void ParticleSystem::setSortMode(SortMode mode)
534 inline double ParticleSystem::getVisibilityDistance() const
536 return _visibilityDistance;
539 inline void ParticleSystem::setVisibilityDistance(double distance)
541 _visibilityDistance = distance;
542 if (_useShaders) _dirty_uniforms = true;