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

Revision 9728, 13.4 kB (checked in by robert, 6 years ago)

Merged from OSG-2.8 branch changes to the use of ReadWriteMutex? to Mutex in osgParticle::ParticleSystem?.

svn command:

svn merge -r 9725:9726 http://www.openscenegraph.org/svn/osg/OpenSceneGraph/branches/OpenSceneGraph-2.8

  • 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        /// Get the double pass rendering flag.
114        inline bool getDoublePassRendering() const;
115       
116        /** Set the double pass rendering flag.
117            Double pass rendering avoids overdraw problems between particle systems
118            and other opaque objects. If you can render all the particle systems after
119            the opaque objects, then double pass is not necessary and can be turned off (best choice).
120            If you set the default attributes with setDefaultAttributes, then the particle
121            system will fall into a transparent bin.
122        */
123        inline void setDoublePassRendering(bool v);
124       
125        /// Return true if the particle system is frozen.
126        inline bool isFrozen() const;
127       
128        /**    Set or reset the <I>frozen</I> state.
129            When the particle system is frozen, emitters and programs won't do anything on it.
130        */
131        inline void setFrozen(bool v);
132
133        /// Get the number of allocated particles (alive + dead).
134        inline int numParticles() const;
135       
136        /// Get the number of dead particles.
137        inline int numDeadParticles() const;
138
139        /// Get whether all particles are dead       
140        inline bool areAllParticlesDead() const { return numDeadParticles()==numParticles(); }
141       
142        /// Get a pointer to the i-th particle.
143        inline Particle* getParticle(int i);
144       
145        /// Get a const pointer to the i-th particle.
146        inline const Particle* getParticle(int i) const;
147       
148        /// Create a new particle from the specified template (or the default one if <CODE>ptemplate</CODE> is null).
149        inline virtual Particle* createParticle(const Particle* ptemplate);
150       
151        /// Destroy the i-th particle.
152        inline virtual void destroyParticle(int i);
153       
154        /// Reuse the i-th particle.
155        inline virtual void reuseParticle(int i) { _deadparts.push(&(_particles[i])); }
156
157        /// Get the last frame number.
158        inline int getLastFrameNumber() const;
159
160        /// Get a reference to the default particle template.
161        inline Particle& getDefaultParticleTemplate();
162       
163        /// Get a const reference to the default particle template.
164        inline const Particle& getDefaultParticleTemplate() const;
165
166        /// Set the default particle template (particle is copied).
167        inline void setDefaultParticleTemplate(const Particle& p);
168       
169        /// Get whether the particle system can freeze when culled
170        inline bool getFreezeOnCull() const;
171       
172        /// Set whether the particle system can freeze when culled (default is true)
173        inline void setFreezeOnCull(bool v);
174       
175        /** A useful method to set the most common <CODE>StateAttribute</CODE>'s in one call.
176            If <CODE>texturefile</CODE> is empty, then texturing is turned off.
177        */
178        void setDefaultAttributes(const std::string& texturefile = "", bool emissive_particles = true, bool lighting = false, int texture_unit = 0);
179       
180        /// (<B>EXPERIMENTAL</B>) Get the level of detail.
181        inline int getLevelOfDetail() const;
182       
183        /** (<B>EXPERIMENTAL</B>) Set the level of detail. The total number of particles is divided by the detail value to
184            get the actual number of particles to be drawn. This value must be greater than zero.
185        */
186        inline void setLevelOfDetail(int v);
187
188        /// Update the particles. Don't call this directly, use a <CODE>ParticleSystemUpdater</CODE> instead.
189        virtual void update(double dt);
190
191        virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
192
193        virtual osg::BoundingBox computeBound() const;
194       
195#ifdef OSGPARTICLE_USE_ReadWriteMutex
196        typedef OpenThreads::ReadWriteMutex ReadWriterMutex;
197        typedef OpenThreads::ScopedReadLock ScopedReadLock;
198        typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
199#else
200        typedef OpenThreads::Mutex ReadWriterMutex;
201        typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedReadLock;
202        typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedWriteLock;
203#endif
204
205        ReadWriterMutex* getReadWriteMutex() const { return &_readWriteMutex; }
206
207    protected:
208
209        virtual ~ParticleSystem();
210
211        ParticleSystem& operator=(const ParticleSystem&) { return *this; }
212
213        inline void update_bounds(const osg::Vec3& p, float r);
214        void single_pass_render(osg::State& state, const osg::Matrix& modelview) const;
215
216        typedef std::vector<Particle> Particle_vector;
217        typedef std::stack<Particle*> Death_stack;
218
219        Particle_vector _particles;
220        Death_stack _deadparts;
221       
222        osg::BoundingBox _def_bbox;
223       
224        Alignment _alignment;
225        osg::Vec3 _align_X_axis;
226        osg::Vec3 _align_Y_axis;
227        ParticleScaleReferenceFrame _particleScaleReferenceFrame;
228       
229        bool _doublepass;
230        bool _frozen;
231
232        osg::Vec3 _bmin;
233        osg::Vec3 _bmax;
234
235        bool _reset_bounds_flag;
236        bool _bounds_computed;
237
238        Particle _def_ptemp;
239        mutable int _last_frame;
240        bool _freeze_on_cull;
241       
242        int _detail;
243        mutable int _draw_count;
244       
245        mutable ReadWriterMutex _readWriteMutex;
246    };
247   
248    // INLINE FUNCTIONS
249   
250    inline ParticleSystem::Alignment ParticleSystem::getParticleAlignment() const
251    {
252        return _alignment;
253    }
254   
255    inline void ParticleSystem::setParticleAlignment(Alignment a)
256    {
257        _alignment = a;
258    }
259   
260    inline const osg::Vec3& ParticleSystem::getAlignVectorX() const
261    {
262        return _align_X_axis;
263    }
264   
265    inline void ParticleSystem::setAlignVectorX(const osg::Vec3& v)
266    {
267        _align_X_axis = v;
268    }
269
270    inline const osg::Vec3& ParticleSystem::getAlignVectorY() const
271    {
272        return _align_Y_axis;
273    }
274   
275    inline void ParticleSystem::setAlignVectorY(const osg::Vec3& v)
276    {
277        _align_Y_axis = v;
278    }
279   
280    inline void ParticleSystem::setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y)
281    {
282        _align_X_axis = X;
283        _align_Y_axis = Y;
284    }
285
286    inline bool ParticleSystem::isFrozen() const
287    {
288        return _frozen;
289    }
290   
291    inline void ParticleSystem::setFrozen(bool v)
292    {
293        _frozen = v;
294    }
295   
296    inline const osg::BoundingBox& ParticleSystem::getDefaultBoundingBox() const
297    {
298        return _def_bbox;
299    }
300   
301    inline void ParticleSystem::setDefaultBoundingBox(const osg::BoundingBox& bbox)
302    {
303        _def_bbox = bbox;
304    }
305
306    inline bool ParticleSystem::getDoublePassRendering() const
307    {
308        return _doublepass;
309    }
310
311    inline void ParticleSystem::setDoublePassRendering(bool v)
312    {
313        _doublepass = v;
314    }
315
316    inline int ParticleSystem::numParticles() const
317    {
318        return static_cast<int>(_particles.size());
319    }
320
321    inline int ParticleSystem::numDeadParticles() const
322    {
323        return static_cast<int>(_deadparts.size());
324    }
325
326    inline Particle* ParticleSystem::getParticle(int i)
327    {
328        return &_particles[i];
329    }
330
331    inline const Particle* ParticleSystem::getParticle(int i) const
332    {
333        return &_particles[i];
334    }
335
336    inline void ParticleSystem::destroyParticle(int i)
337    {
338        _particles[i].kill();
339    }
340   
341    inline int ParticleSystem::getLastFrameNumber() const
342    {
343        return _last_frame;
344    }
345
346    inline void ParticleSystem::update_bounds(const osg::Vec3& p, float r)
347    {
348        if (_reset_bounds_flag) {
349            _reset_bounds_flag = false;
350            _bmin = p - osg::Vec3(r,r,r);
351            _bmax = p + osg::Vec3(r,r,r);
352        } else {
353            if (p.x() - r < _bmin.x()) _bmin.x() = p.x() - r;
354            if (p.y() - r < _bmin.y()) _bmin.y() = p.y() - r;
355            if (p.z() - r < _bmin.z()) _bmin.z() = p.z() - r;
356            if (p.x() + r > _bmax.x()) _bmax.x() = p.x() + r;
357            if (p.y() + r > _bmax.y()) _bmax.y() = p.y() + r;
358            if (p.z() + r > _bmax.z()) _bmax.z() = p.z() + r;
359        }
360        if (!_bounds_computed)
361            _bounds_computed = true;
362    }
363
364    inline Particle& ParticleSystem::getDefaultParticleTemplate()
365    {
366        return _def_ptemp;
367    }
368
369    inline const Particle& ParticleSystem::getDefaultParticleTemplate() const
370    {
371        return _def_ptemp;
372    }
373
374    inline void ParticleSystem::setDefaultParticleTemplate(const Particle& p)
375    {
376        _def_ptemp = p;
377    }
378   
379    inline bool ParticleSystem::getFreezeOnCull() const
380    {
381        return _freeze_on_cull;
382    }
383   
384    inline void ParticleSystem::setFreezeOnCull(bool v)
385    {
386        _freeze_on_cull = v;
387    }
388   
389    inline int ParticleSystem::getLevelOfDetail() const
390    {
391        return _detail;
392    }
393   
394    inline void ParticleSystem::setLevelOfDetail(int v)
395    {
396        if (v < 1) v = 1;
397        _detail = v;
398    }
399   
400    // I'm not sure this function should be inlined...
401   
402    inline Particle* ParticleSystem::createParticle(const Particle* ptemplate)
403    {
404        // is there any dead particle?
405        if (!_deadparts.empty()) {
406
407            // retrieve a pointer to the last dead particle
408            Particle* P = _deadparts.top();
409
410            // create a new (alive) particle in the same place
411            *P = ptemplate? *ptemplate: _def_ptemp;
412
413            // remove the pointer from the death stack
414            _deadparts.pop();
415            return P;
416
417        } else {
418
419            // add a new particle to the vector
420            _particles.push_back(ptemplate? *ptemplate: _def_ptemp);
421            return &_particles.back();
422        }
423    }
424
425
426}
427
428#endif
Note: See TracBrowser for help on using the browser.