123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
- *
- * This library is open source and may be redistributed and/or modified under
- * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
- * (at your option) any later version. The full license is in LICENSE file
- * included with this distribution, and on the openscenegraph.org website.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * OpenSceneGraph Public License for more details.
- */
- //osgParticle - Copyright (C) 2002 Marco Jez
- #ifndef OSGPARTICLE_PARTICLESYSTEM
- #define OSGPARTICLE_PARTICLESYSTEM 1
- #include <osgParticle/Export>
- #include <osgParticle/Particle>
- #include <vector>
- #include <stack>
- #include <algorithm>
- #include <string>
- #include <osg/Object>
- #include <osg/Drawable>
- #include <osg/CopyOp>
- #include <osg/State>
- #include <osg/Vec3>
- #include <osg/BoundingBox>
- // 9th Febrary 2009, disabled the use of ReadWriteMutex as it looks like this
- // is introducing threading problems due to threading problems in OpenThreads::ReadWriteMutex.
- // #define OSGPARTICLE_USE_ReadWriteMutex
- #ifdef OSGPARTICLE_USE_ReadWriteMutex
- #include <OpenThreads/ReadWriteMutex>
- #else
- #include <OpenThreads/Mutex>
- #include <OpenThreads/ScopedLock>
- #endif
- 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:
- enum Alignment {
- BILLBOARD,
- FIXED
- };
- ParticleSystem();
- ParticleSystem(const ParticleSystem& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
- META_Object(osgParticle, ParticleSystem);
- /// Get the alignment type of particles.
- inline Alignment getParticleAlignment() const;
- /// Set the alignment type of particles.
- inline void setParticleAlignment(Alignment a);
- /// Get the X-axis alignment vector.
- inline const osg::Vec3& getAlignVectorX() const;
- /// Set the X-axis alignment vector.
- inline void setAlignVectorX(const osg::Vec3& v);
- /// Get the Y-axis alignment vector.
- inline const osg::Vec3& getAlignVectorY() const;
- /// Set the Y-axis alignment vector.
- inline void setAlignVectorY(const osg::Vec3& v);
- /// Set the alignment vectors.
- inline void setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y);
- enum ParticleScaleReferenceFrame
- {
- LOCAL_COORDINATES,
- WORLD_COORDINATES
- };
- /** Set whether the particles should be scaled relative to world coordaintes or local coordinates.*/
- void setParticleScaleReferenceFrame(ParticleScaleReferenceFrame rf) { _particleScaleReferenceFrame = rf; }
- /** Get whether the particles should be scaled relative to world coordaintes or local coordinates.*/
- ParticleScaleReferenceFrame getParticleScaleReferenceFrame() const { return _particleScaleReferenceFrame; }
- /// 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);
- /// Return true if we use vertex arrays for rendering particles.
- bool getUseVertexArray() const { return _useVertexArray; }
- /** Set to use vertex arrays for rendering particles.
- Lots of variables will be omitted: particles' shape, alive or not, visibility distance, and so on,
- so the rendering result is not as good as we wish (although it's fast than using glBegin/glEnd).
- We had better use this for GLSL shaders, in which particle parameters will be kept as uniforms.
- This method is called automatically by <CODE>setDefaultAttributesUsingShaders()</CODE>.
- */
- void setUseVertexArray(bool v) { _useVertexArray = v; }
- /// Return true if shaders are required.
- bool getUseShaders() const { return _useShaders; }
- /** Set to use GLSL shaders for rendering particles.
- Particles' parameters will be used as shader attribute arrays, and necessary variables, including
- the visibility distance, texture, etc, will be used and updated as uniforms.
- */
- void setUseShaders(bool v) { _useShaders = v; _dirty_uniforms = true; }
- /// 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.
- bool getFrozen() const { return _frozen; }
- inline bool isFrozen() const;
- /** Set or reset the <I>frozen</I> 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 whether all particles are dead
- inline bool areAllParticlesDead() const { return numDeadParticles()==numParticles(); }
- /// 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 <CODE>ptemplate</CODE> is null).
- virtual Particle* createParticle(const Particle* ptemplate);
- /// Destroy the i-th particle.
- inline virtual void destroyParticle(int i);
- /// Reuse the i-th particle.
- inline virtual void reuseParticle(int i) { _deadparts.push(&(_particles[i])); }
- /// Get the last frame number.
- inline unsigned int getLastFrameNumber() const;
- /// Get the unique delta time for emitters and updaters to use
- inline double& getDeltaTime( double currentTime );
- /// Get a reference to the default particle template.
- inline Particle& getDefaultParticleTemplate();
- /// Get a const 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 <CODE>StateAttribute</CODE>'s in one call.
- If <CODE>texturefile</CODE> is empty, then texturing is turned off.
- */
- void setDefaultAttributes(const std::string& texturefile = "", bool emissive_particles = true, bool lighting = false, int texture_unit = 0);
- /** A useful method to set the most common <CODE>StateAttribute</CODE> and use GLSL shaders to draw particles.
- At present, when enabling shaders in the particle system, user-defined shapes will not be usable.
- If <CODE>texturefile</CODE> is empty, then texturing is turned off.
- */
- void setDefaultAttributesUsingShaders(const std::string& texturefile = "", bool emissive_particles = true, int texture_unit = 0);
- /// (<B>EXPERIMENTAL</B>) Get the level of detail.
- inline int getLevelOfDetail() const;
- /** (<B>EXPERIMENTAL</B>) 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);
- enum SortMode
- {
- NO_SORT,
- SORT_FRONT_TO_BACK,
- SORT_BACK_TO_FRONT
- };
- /// Get the sort mode.
- inline SortMode getSortMode() const;
- /** Set the sort mode. It will force resorting the particle list by the Z direction of the view coordinates.
- This can be used for the purpose of transparent rendering or <CODE>setVisibilityDistance()</CODE>.
- */
- inline void setSortMode(SortMode mode);
- /// Get the visibility distance.
- inline double getVisibilityDistance() const;
- /** Set the visibility distance which allows the particles to be rendered only when depth is inside the distance.
- When using shaders, it can work well directly; otherwise the sort mode should also be set to pre-compute depth.
- */
- inline void setVisibilityDistance(double distance);
- /// Update the particles. Don't call this directly, use a <CODE>ParticleSystemUpdater</CODE> instead.
- virtual void update(double dt, osg::NodeVisitor& nv);
- virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
- virtual osg::BoundingBox computeBoundingBox() const;
- #ifdef OSGPARTICLE_USE_ReadWriteMutex
- typedef OpenThreads::ReadWriteMutex ReadWriterMutex;
- typedef OpenThreads::ScopedReadLock ScopedReadLock;
- typedef OpenThreads::ScopedWriteLock ScopedWriteLock;
- #else
- typedef OpenThreads::Mutex ReadWriterMutex;
- typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedReadLock;
- typedef OpenThreads::ScopedLock<OpenThreads::Mutex> ScopedWriteLock;
- #endif
- ReadWriterMutex* getReadWriteMutex() const { return &_readWriteMutex; }
- /** Resize any per context GLObject buffers to specified size. */
- virtual void resizeGLObjectBuffers(unsigned int maxSize);
- /** If State is non-zero, this function releases OpenGL objects for
- * the specified graphics context. Otherwise, releases OpenGL objects
- * for all graphics contexts. */
- virtual void releaseGLObjects(osg::State* state=0) const;
- virtual osg::VertexArrayState* createVertexArrayStateImplementation(osg::RenderInfo& renderInfo) const;
- void adjustEstimatedMaxNumOfParticles(int delta) { _estimatedMaxNumOfParticles += delta; }
- void setEstimatedMaxNumOfParticles(int num) { _estimatedMaxNumOfParticles = num; }
- int getEstimatedMaxNumOfParticles() const { return _estimatedMaxNumOfParticles; }
- protected:
- virtual ~ParticleSystem();
- ParticleSystem& operator=(const ParticleSystem&) { return *this; }
- inline void update_bounds(const osg::Vec3& p, float r);
- typedef std::vector<Particle> Particle_vector;
- typedef std::stack<Particle*> Death_stack;
- Particle_vector _particles;
- Death_stack _deadparts;
- osg::BoundingBox _def_bbox;
- Alignment _alignment;
- osg::Vec3 _align_X_axis;
- osg::Vec3 _align_Y_axis;
- ParticleScaleReferenceFrame _particleScaleReferenceFrame;
- bool _useVertexArray;
- bool _useShaders;
- bool _dirty_uniforms;
- bool _doublepass;
- bool _frozen;
- osg::Vec3 _bmin;
- osg::Vec3 _bmax;
- bool _reset_bounds_flag;
- bool _bounds_computed;
- Particle _def_ptemp;
- mutable unsigned int _last_frame;
- mutable bool _dirty_dt;
- bool _freeze_on_cull;
- double _t0;
- double _dt;
- int _detail;
- SortMode _sortMode;
- double _visibilityDistance;
- mutable ReadWriterMutex _readWriteMutex;
- int _estimatedMaxNumOfParticles;
- struct OSGPARTICLE_EXPORT ArrayData
- {
- ArrayData();
- void init();
- void init3();
- void reserve(unsigned int numVertices);
- void resize(unsigned int numVertices);
- void resizeGLObjectBuffers(unsigned int maxSize);
- void releaseGLObjects(osg::State* state);
- void clear();
- void dirty();
- void dispatchArrays(osg::State& state);
- void dispatchPrimitives();
- osg::ref_ptr<osg::BufferObject> vertexBufferObject;
- osg::ref_ptr<osg::Vec3Array> vertices;
- osg::ref_ptr<osg::Vec3Array> normals;
- osg::ref_ptr<osg::Vec4Array> colors;
- osg::ref_ptr<osg::Vec2Array> texcoords2;
- osg::ref_ptr<osg::Vec3Array> texcoords3;
- typedef std::pair<GLenum, unsigned int> ModeCount;
- typedef std::vector<ModeCount> Primitives;
- Primitives primitives;
- };
- typedef osg::buffered_object< ArrayData > BufferedArrayData;
- mutable BufferedArrayData _bufferedArrayData;
- };
- // INLINE FUNCTIONS
- inline ParticleSystem::Alignment ParticleSystem::getParticleAlignment() const
- {
- return _alignment;
- }
- inline void ParticleSystem::setParticleAlignment(Alignment a)
- {
- _alignment = a;
- }
- inline const osg::Vec3& ParticleSystem::getAlignVectorX() const
- {
- return _align_X_axis;
- }
- inline void ParticleSystem::setAlignVectorX(const osg::Vec3& v)
- {
- _align_X_axis = v;
- }
- inline const osg::Vec3& ParticleSystem::getAlignVectorY() const
- {
- return _align_Y_axis;
- }
- inline void ParticleSystem::setAlignVectorY(const osg::Vec3& v)
- {
- _align_Y_axis = v;
- }
- inline void ParticleSystem::setAlignVectors(const osg::Vec3& X, const osg::Vec3& Y)
- {
- _align_X_axis = X;
- _align_Y_axis = Y;
- }
- 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<int>(_particles.size());
- }
- inline int ParticleSystem::numDeadParticles() const
- {
- return static_cast<int>(_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 unsigned int ParticleSystem::getLastFrameNumber() const
- {
- return _last_frame;
- }
- inline double& ParticleSystem::getDeltaTime( double currentTime )
- {
- if ( _dirty_dt )
- {
- _dt = currentTime - _t0;
- if ( _dt<0.0 ) _dt = 0.0;
- _t0 = currentTime;
- _dirty_dt = false;
- }
- return _dt;
- }
- inline void ParticleSystem::update_bounds(const osg::Vec3& p, float r)
- {
- if (_reset_bounds_flag) {
- _reset_bounds_flag = false;
- _bmin = p - osg::Vec3(r,r,r);
- _bmax = p + osg::Vec3(r,r,r);
- } else {
- if (p.x() - r < _bmin.x()) _bmin.x() = p.x() - r;
- if (p.y() - r < _bmin.y()) _bmin.y() = p.y() - r;
- if (p.z() - r < _bmin.z()) _bmin.z() = p.z() - r;
- if (p.x() + r > _bmax.x()) _bmax.x() = p.x() + r;
- if (p.y() + r > _bmax.y()) _bmax.y() = p.y() + r;
- if (p.z() + r > _bmax.z()) _bmax.z() = p.z() + r;
- }
- if (!_bounds_computed)
- _bounds_computed = true;
- }
- inline Particle& ParticleSystem::getDefaultParticleTemplate()
- {
- return _def_ptemp;
- }
- 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;
- }
- inline ParticleSystem::SortMode ParticleSystem::getSortMode() const
- {
- return _sortMode;
- }
- inline void ParticleSystem::setSortMode(SortMode mode)
- {
- _sortMode = mode;
- }
- inline double ParticleSystem::getVisibilityDistance() const
- {
- return _visibilityDistance;
- }
- inline void ParticleSystem::setVisibilityDistance(double distance)
- {
- _visibilityDistance = distance;
- if (_useShaders) _dirty_uniforms = true;
- }
- }
- #endif
|