root/OpenSceneGraph/trunk/include/osgParticle/ParticleSystem @ 13041

Revision 13041, 16.9 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
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.
7 *
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.
12*/
13//osgParticle - Copyright (C) 2002 Marco Jez
14
15#ifndef OSGPARTICLE_PARTICLESYSTEM
16#define OSGPARTICLE_PARTICLESYSTEM 1
17
18#include <osgParticle/Export>
19#include <osgParticle/Particle>
20
21#include <vector>
22#include <stack>
23#include <algorithm>
24#include <string>
25
26#include <osg/Object>
27#include <osg/Drawable>
28#include <osg/CopyOp>
29#include <osg/State>
30#include <osg/Vec3>
31#include <osg/BoundingBox>
32
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
36
37#ifdef OSGPARTICLE_USE_ReadWriteMutex
38    #include <OpenThreads/ReadWriteMutex>
39#else
40    #include <OpenThreads/Mutex>
41    #include <OpenThreads/ScopedLock>
42#endif
43
44
45namespace osgParticle
46{
47
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).
53    */
54    class OSGPARTICLE_EXPORT ParticleSystem: public osg::Drawable {
55    public:
56
57        enum Alignment {
58            BILLBOARD,
59            FIXED
60        };
61
62        ParticleSystem();
63        ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
64
65        META_Object(osgParticle, ParticleSystem);
66
67        /// Get the alignment type of particles.
68        inline Alignment getParticleAlignment() const;
69
70        /// Set the alignment type of particles.
71        inline void setParticleAlignment(Alignment a);
72
73        /// Get the X-axis alignment vector.
74        inline const osg::Vec3& getAlignVectorX() const;
75
76        /// Set the X-axis alignment vector.
77        inline void setAlignVectorX(const osg::Vec3& v);
78
79        /// Get the Y-axis alignment vector.
80        inline const osg::Vec3& getAlignVectorY() const;
81
82        /// Set the Y-axis alignment vector.
83        inline void setAlignVectorY(const osg::Vec3& v);
84
85        /// Set the alignment vectors.
86        inline void setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y);
87
88
89
90        enum ParticleScaleReferenceFrame
91        {
92            LOCAL_COORDINATES,
93            WORLD_COORDINATES
94        };
95
96        /** Set whether the particles should be scaled relative to world coordaintes or local coordinates.*/
97        void setParticleScaleReferenceFrame(ParticleScaleReferenceFrame rf) { _particleScaleReferenceFrame = rf; }
98
99        /** Get whether the particles should be scaled relative to world coordaintes or local coordinates.*/
100        ParticleScaleReferenceFrame getParticleScaleReferenceFrame() const { return _particleScaleReferenceFrame; }
101
102
103
104        /// Get the default bounding box
105        inline const osg::BoundingBox& getDefaultBoundingBox() const;
106
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.
110        */
111        inline void setDefaultBoundingBox(const osg::BoundingBox& bbox);
112
113        /// Return true if we use vertex arrays for rendering particles.
114        bool getUseVertexArray() const { return _useVertexArray; }
115
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>.
121        */
122        void setUseVertexArray(bool v) { _useVertexArray = v; }
123
124        /// Return true if shaders are required.
125        bool getUseShaders() const { return _useShaders; }
126
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.
130        */
131        void setUseShaders(bool v) { _useShaders = v; _dirty_uniforms = true; }
132
133        /// Get the double pass rendering flag.
134        inline bool getDoublePassRendering() const;
135
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.
142        */
143        inline void setDoublePassRendering(bool v);
144
145        /// Return true if the particle system is frozen.
146        bool getFrozen() const { return _frozen; }
147        inline bool isFrozen() const;
148
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.
151        */
152        inline void setFrozen(bool v);
153
154        /// Get the number of allocated particles (alive + dead).
155        inline int numParticles() const;
156
157        /// Get the number of dead particles.
158        inline int numDeadParticles() const;
159
160        /// Get whether all particles are dead
161        inline bool areAllParticlesDead() const { return numDeadParticles()==numParticles(); }
162
163        /// Get a pointer to the i-th particle.
164        inline Particle* getParticle(int i);
165
166        /// Get a const pointer to the i-th particle.
167        inline const Particle* getParticle(int i) const;
168
169        /// Create a new particle from the specified template (or the default one if <CODE>ptemplate</CODE> is null).
170        inline virtual Particle* createParticle(const Particle* ptemplate);
171
172        /// Destroy the i-th particle.
173        inline virtual void destroyParticle(int i);
174
175        /// Reuse the i-th particle.
176        inline virtual void reuseParticle(int i) { _deadparts.push(&(_particles[i])); }
177
178        /// Get the last frame number.
179        inline unsigned int getLastFrameNumber() const;
180
181        /// Get the unique delta time for emitters and updaters to use
182        inline double& getDeltaTime( double currentTime );
183
184        /// Get a reference to the default particle template.
185        inline Particle& getDefaultParticleTemplate();
186
187        /// Get a const reference to the default particle template.
188        inline const Particle& getDefaultParticleTemplate() const;
189
190        /// Set the default particle template (particle is copied).
191        inline void setDefaultParticleTemplate(const Particle& p);
192
193        /// Get whether the particle system can freeze when culled
194        inline bool getFreezeOnCull() const;
195
196        /// Set whether the particle system can freeze when culled (default is true)
197        inline void setFreezeOnCull(bool v);
198
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.
201        */
202        void setDefaultAttributes(const std::string& texturefile = "", bool emissive_particles = true, bool lighting = false, int texture_unit = 0);
203
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.
207        */
208        void setDefaultAttributesUsingShaders(const std::string& texturefile = "", bool emissive_particles = true, int texture_unit = 0);
209
210        /// (<B>EXPERIMENTAL</B>) Get the level of detail.
211        inline int getLevelOfDetail() const;
212
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.
215        */
216        inline void setLevelOfDetail(int v);
217
218        enum SortMode
219        {
220            NO_SORT,
221            SORT_FRONT_TO_BACK,
222            SORT_BACK_TO_FRONT
223        };
224
225        /// Get the sort mode.
226        inline SortMode getSortMode() const;
227
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>.
230        */
231        inline void setSortMode(SortMode mode);
232
233        /// Get the visibility distance.
234        inline double getVisibilityDistance() const;
235
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.
238        */
239        inline void setVisibilityDistance(double distance);
240
241        /// Update the particles. Don't call this directly, use a <CODE>ParticleSystemUpdater</CODE> instead.
242        virtual void update(double dt, osg::NodeVisitor& nv);
243
244        virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
245
246        virtual osg::BoundingBox computeBound() const;
247
248#ifdef OSGPARTICLE_USE_ReadWriteMutex
249        typedef OpenThreads::ReadWriteMutex ReadWriterMutex;
250        typedef OpenThreads::ScopedReadLock ScopedReadLock;
251        typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
252#else
253        typedef OpenThreads::Mutex ReadWriterMutex;
254        typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedReadLock;
255        typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedWriteLock;
256#endif
257
258        ReadWriterMutex* getReadWriteMutex() const { return &_readWriteMutex; }
259
260    protected:
261
262        virtual ~ParticleSystem();
263
264        ParticleSystem& operator=(const ParticleSystem&) { return *this; }
265
266        inline void update_bounds(const osg::Vec3& p, float r);
267        void single_pass_render(osg::RenderInfo& renderInfo, const osg::Matrix& modelview) const;
268        void render_vertex_array(osg::RenderInfo& renderInfo) const;
269
270        typedef std::vector<Particle> Particle_vector;
271        typedef std::stack<Particle*> Death_stack;
272
273        Particle_vector _particles;
274        Death_stack _deadparts;
275
276        osg::BoundingBox _def_bbox;
277
278        Alignment _alignment;
279        osg::Vec3 _align_X_axis;
280        osg::Vec3 _align_Y_axis;
281        ParticleScaleReferenceFrame _particleScaleReferenceFrame;
282
283        bool _useVertexArray;
284        bool _useShaders;
285        bool _dirty_uniforms;
286
287        bool _doublepass;
288        bool _frozen;
289
290        osg::Vec3 _bmin;
291        osg::Vec3 _bmax;
292
293        bool _reset_bounds_flag;
294        bool _bounds_computed;
295
296        Particle _def_ptemp;
297        mutable unsigned int _last_frame;
298        mutable bool _dirty_dt;
299        bool _freeze_on_cull;
300
301        double _t0;
302        double _dt;
303
304        int _detail;
305        SortMode _sortMode;
306        double _visibilityDistance;
307
308        mutable int _draw_count;
309
310        mutable ReadWriterMutex _readWriteMutex;
311    };
312
313    // INLINE FUNCTIONS
314
315    inline ParticleSystem::Alignment ParticleSystem::getParticleAlignment() const
316    {
317        return _alignment;
318    }
319
320    inline void ParticleSystem::setParticleAlignment(Alignment a)
321    {
322        _alignment = a;
323    }
324
325    inline const osg::Vec3& ParticleSystem::getAlignVectorX() const
326    {
327        return _align_X_axis;
328    }
329
330    inline void ParticleSystem::setAlignVectorX(const osg::Vec3& v)
331    {
332        _align_X_axis = v;
333    }
334
335    inline const osg::Vec3& ParticleSystem::getAlignVectorY() const
336    {
337        return _align_Y_axis;
338    }
339
340    inline void ParticleSystem::setAlignVectorY(const osg::Vec3& v)
341    {
342        _align_Y_axis = v;
343    }
344
345    inline void ParticleSystem::setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y)
346    {
347        _align_X_axis = X;
348        _align_Y_axis = Y;
349    }
350
351    inline bool ParticleSystem::isFrozen() const
352    {
353        return _frozen;
354    }
355
356    inline void ParticleSystem::setFrozen(bool v)
357    {
358        _frozen = v;
359    }
360
361    inline const osg::BoundingBox& ParticleSystem::getDefaultBoundingBox() const
362    {
363        return _def_bbox;
364    }
365
366    inline void ParticleSystem::setDefaultBoundingBox(const osg::BoundingBox& bbox)
367    {
368        _def_bbox = bbox;
369    }
370
371    inline bool ParticleSystem::getDoublePassRendering() const
372    {
373        return _doublepass;
374    }
375
376    inline void ParticleSystem::setDoublePassRendering(bool v)
377    {
378        _doublepass = v;
379    }
380
381    inline int ParticleSystem::numParticles() const
382    {
383        return static_cast<int>(_particles.size());
384    }
385
386    inline int ParticleSystem::numDeadParticles() const
387    {
388        return static_cast<int>(_deadparts.size());
389    }
390
391    inline Particle* ParticleSystem::getParticle(int i)
392    {
393        return &_particles[i];
394    }
395
396    inline const Particle* ParticleSystem::getParticle(int i) const
397    {
398        return &_particles[i];
399    }
400
401    inline void ParticleSystem::destroyParticle(int i)
402    {
403        _particles[i].kill();
404    }
405
406    inline unsigned int ParticleSystem::getLastFrameNumber() const
407    {
408        return _last_frame;
409    }
410
411    inline double& ParticleSystem::getDeltaTime( double currentTime )
412    {
413        if ( _dirty_dt )
414        {
415            _dt = currentTime - _t0;
416            if ( _dt<0.0 ) _dt = 0.0;
417
418            _t0 = currentTime;
419            _dirty_dt = false;
420        }
421        return _dt;
422    }
423
424    inline void ParticleSystem::update_bounds(const osg::Vec3& p, float r)
425    {
426        if (_reset_bounds_flag) {
427            _reset_bounds_flag = false;
428            _bmin = p - osg::Vec3(r,r,r);
429            _bmax = p + osg::Vec3(r,r,r);
430        } else {
431            if (p.x() - r < _bmin.x()) _bmin.x() = p.x() - r;
432            if (p.y() - r < _bmin.y()) _bmin.y() = p.y() - r;
433            if (p.z() - r < _bmin.z()) _bmin.z() = p.z() - r;
434            if (p.x() + r > _bmax.x()) _bmax.x() = p.x() + r;
435            if (p.y() + r > _bmax.y()) _bmax.y() = p.y() + r;
436            if (p.z() + r > _bmax.z()) _bmax.z() = p.z() + r;
437        }
438        if (!_bounds_computed)
439            _bounds_computed = true;
440    }
441
442    inline Particle& ParticleSystem::getDefaultParticleTemplate()
443    {
444        return _def_ptemp;
445    }
446
447    inline const Particle& ParticleSystem::getDefaultParticleTemplate() const
448    {
449        return _def_ptemp;
450    }
451
452    inline void ParticleSystem::setDefaultParticleTemplate(const Particle& p)
453    {
454        _def_ptemp = p;
455    }
456
457    inline bool ParticleSystem::getFreezeOnCull() const
458    {
459        return _freeze_on_cull;
460    }
461
462    inline void ParticleSystem::setFreezeOnCull(bool v)
463    {
464        _freeze_on_cull = v;
465    }
466
467    inline int ParticleSystem::getLevelOfDetail() const
468    {
469        return _detail;
470    }
471
472    inline void ParticleSystem::setLevelOfDetail(int v)
473    {
474        if (v < 1) v = 1;
475        _detail = v;
476    }
477
478    inline ParticleSystem::SortMode ParticleSystem::getSortMode() const
479    {
480        return _sortMode;
481    }
482
483    inline void ParticleSystem::setSortMode(SortMode mode)
484    {
485        _sortMode = mode;
486    }
487
488    inline double ParticleSystem::getVisibilityDistance() const
489    {
490        return _visibilityDistance;
491    }
492
493    inline void ParticleSystem::setVisibilityDistance(double distance)
494    {
495        _visibilityDistance = distance;
496        if (_useShaders) _dirty_uniforms = true;
497    }
498
499    // I'm not sure this function should be inlined...
500
501    inline Particle* ParticleSystem::createParticle(const Particle* ptemplate)
502    {
503        // is there any dead particle?
504        if (!_deadparts.empty()) {
505
506            // retrieve a pointer to the last dead particle
507            Particle* P = _deadparts.top();
508
509            // create a new (alive) particle in the same place
510            *P = ptemplate? *ptemplate: _def_ptemp;
511
512            // remove the pointer from the death stack
513            _deadparts.pop();
514            return P;
515
516        } else {
517
518            // add a new particle to the vector
519            _particles.push_back(ptemplate? *ptemplate: _def_ptemp);
520            return &_particles.back();
521        }
522    }
523
524
525}
526
527#endif
Note: See TracBrowser for help on using the browser.