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_PARTICLE
16#define OSGPARTICLE_PARTICLE 1
17
18#include <osgParticle/Export>
19#include <osgParticle/Interpolator>
20#include <osgParticle/range>
21
22#include <osg/ref_ptr>
23#include <osg/Vec3>
24#include <osg/Vec4>
25#include <osg/Matrix>
26
27namespace osgParticle
28{
29
30    // forward declare so we can reference it
31    class ParticleSystem;
32
33    /**    Implementation of a <B>particle</B>.
34        Objects of this class are particles, they have some graphical properties
35        and some physical properties. Particles are created by emitters and then placed
36        into Particle Systems, where they live and get updated at each frame.
37        Particles can either live forever (lifeTime < 0), or die after a specified
38        time (lifeTime >= 0). For each property which is defined as a range of values, a
39        "current" value will be evaluated at each frame by interpolating the <I>min</I>
40        and <I>max</I> values so that <I>curr_value = min</I> when <I>t == 0</I>, and
41        <I>curr_value = max</I> when <I>t == lifeTime</I>.
42        You may customize the interpolator objects to achieve any kind of transition.
43        If you want the particle to live forever, set its lifetime to any value <= 0;
44        in that case, no interpolation is done to compute real-time properties, and only
45        minimum values are used.
46    */
47    class OSGPARTICLE_EXPORT Particle {
48        friend class ParticleSystem;
49    public:
50
51        enum
52        {
53            INVALID_INDEX = -1
54        };
55
56        /**
57         Shape of particles.
58         NOTE: the LINE shape should be used in conjunction with FIXED alignment mode (see ParticleSystem).
59        */
60        enum Shape {
61            POINT,              // uses GL_POINTS as primitive
62            QUAD,               // uses GL_QUADS as primitive
63            QUAD_TRIANGLESTRIP, // no longer supported, falls back to QUAD
64            HEXAGON,            // no longer supported, falls back to QUAD
65            LINE,               // uses GL_LINES to draw line segments that point to the direction of motion
66            USER                // no longer supported, falls back to QUAD
67        };
68
69        Particle();
70
71        /// Get the shape of the particle.
72        inline Shape getShape() const;
73
74        /// Set the shape of the particle.
75        inline void setShape(Shape s);
76
77        /// Get whether the particle is still alive.
78        inline bool isAlive() const;
79
80        /// Get the life time of the particle (in seconds).
81        inline double getLifeTime() const;
82
83        /// Get the age of the particle (in seconds).
84        inline double getAge() const;
85
86        /// Get the minimum and maximum values for polygon size.
87        inline const rangef& getSizeRange() const;
88
89        /// Get the minimum and maximum values for alpha.
90        inline const rangef& getAlphaRange() const;
91
92        /// Get the minimum and maximum values for color.
93        inline const rangev4& getColorRange() const;
94
95        /// Get the interpolator for computing the size of polygons.
96        inline const Interpolator* getSizeInterpolator() const;
97
98        /// Get the interpolator for computing alpha values.
99        inline const Interpolator* getAlphaInterpolator() const;
100
101        /// Get the interpolator for computing color values.
102        inline const Interpolator* getColorInterpolator() const;
103
104        /** Get the physical radius of the particle.
105            For built-in operators to work correctly, lengths must be expressed in meters.
106        */
107        inline float getRadius() const;
108
109        /** Get the mass of the particle.
110            For built-in operators to work correctly, remember that the mass is expressed in kg.
111        */
112        inline float getMass() const;
113
114        /// Get <CODE>1 / getMass()</CODE>.
115        inline float getMassInv() const;
116
117        /// Get the position vector.
118        inline const osg::Vec3& getPosition() const;
119
120        /**    Get the velocity vector.
121            For built-in operators to work correctly, remember that velocity components are expressed
122            in meters per second.
123        */
124        inline const osg::Vec3& getVelocity() const;
125
126        /// Get the previous position (the position before last update).
127        inline const osg::Vec3& getPreviousPosition() const;
128
129        /// Get the angle vector.
130        inline const osg::Vec3& getAngle() const;
131
132        /// Get the rotational velocity vector.
133        inline const osg::Vec3& getAngularVelocity() const;
134
135        /// Get the previous angle vector.
136        inline const osg::Vec3& getPreviousAngle() const;
137
138        /// Get the current color
139        inline const osg::Vec4& getCurrentColor() const { return _current_color; }
140
141        /// Get the current alpha
142        inline float getCurrentAlpha() const { return _current_alpha; }
143
144        /// Get the s texture coordinate of the bottom left of the particle
145        inline float getSTexCoord() const { return _s_coord; }
146
147        /// Get the t texture coordinate of the bottom left of the particle
148        inline float getTTexCoord() const { return _t_coord; }
149
150        /// Get the texture coordinate width of the particle
151        inline float getSTexTile() const { return _s_tile; }
152
153        /// Get the texture coordinate height of the particle
154        inline float getTTexTile() const { return _t_tile; }
155
156
157        /// Get width of texture tile
158        inline int getTileS() const;
159
160        /// Get height of texture tile
161        inline int getTileT() const;
162
163        /// Get number of texture tiles
164        inline int getNumTiles() const { return _end_tile - _start_tile + 1; }
165
166        /** Kill the particle on next update
167            NOTE: after calling this function, the <CODE>isAlive()</CODE> method will still
168            return true until the particle is updated again.
169        */
170        inline void kill();
171
172        /// Set the life time of the particle.
173        inline void setLifeTime(double t);
174
175        /// Set the minimum and maximum values for polygon size.
176        inline void setSizeRange(const rangef& r);
177
178        /// Set the minimum and maximum values for alpha.
179        inline void setAlphaRange(const rangef& r);
180
181        /// Set the minimum and maximum values for color.
182        inline void setColorRange(const rangev4& r);
183
184        /// Set the interpolator for computing size values.
185        inline void setSizeInterpolator(Interpolator* ri);
186        template<class T> void setSizeInterpolator(const osg::ref_ptr<T>& ri) { setSizeInterpolator(ri.get()); }
187
188        /// Set the interpolator for computing alpha values.
189        inline void setAlphaInterpolator(Interpolator* ai);
190        template<class T> void setAlphaInterpolator(const osg::ref_ptr<T>& ri) { setAlphaInterpolator(ri.get()); }
191
192        /// Set the interpolator for computing color values.
193        inline void setColorInterpolator(Interpolator* ci);
194        template<class T> void setColorInterpolator(const osg::ref_ptr<T>& ri) { setColorInterpolator(ri.get()); }
195
196        /** Set the physical radius of the particle.
197            For built-in operators to work correctly, lengths must be expressed in meters.
198        */
199        inline void setRadius(float r);
200
201        /** Set the mass of the particle.
202            For built-in operators to work correctly, remember that the mass is expressed in kg.
203        */
204        inline void setMass(float m);
205
206        /// Set the position vector.
207        inline void setPosition(const osg::Vec3& p);
208
209        /**    Set the velocity vector.
210            For built-in operators to work correctly, remember that velocity components are expressed
211            in meters per second.
212        */
213        inline void setVelocity(const osg::Vec3& v);
214
215        /// Add a vector to the velocity vector.
216        inline void addVelocity(const osg::Vec3& dv);
217
218        /// Transform position and velocity vectors by a matrix.
219        inline void transformPositionVelocity(const osg::Matrix& xform);
220
221        /// Transform position and velocity vectors by a combination of two matrices
222        void transformPositionVelocity(const osg::Matrix& xform1, const osg::Matrix& xform2, float r);
223
224        /// Set the angle vector.
225        inline void setAngle(const osg::Vec3& a);
226
227        /**
228          Set the angular velocity vector.
229          Components x, y and z are angles of rotation around the respective axis (in radians).
230        */
231        inline void setAngularVelocity(const osg::Vec3& v);
232
233        /// Add a vector to the angular velocity vector.
234        inline void addAngularVelocity(const osg::Vec3& dv);
235
236        /// Transform angle and angularVelocity vectors by a matrix.
237        inline void transformAngleVelocity(const osg::Matrix& xform);
238
239        /** Update the particle (don't call this method manually).
240            This method is called automatically by <CODE>ParticleSystem::update()</CODE>; it
241            updates the graphical properties of the particle for the current time,
242            checks whether the particle is still alive, and then updates its position
243            by computing <I>P = P + V * dt</I> (where <I>P</I> is the position and <I>V</I> is the velocity).
244        */
245        bool update(double dt, bool onlyTimeStamp);
246
247        /// Get the current (interpolated) polygon size. Valid only after the first call to update().
248        inline float getCurrentSize() const;
249
250        /// Specify how the particle texture is tiled.
251        /// All tiles in the given range are sequentially displayed during the lifetime
252        /// of the particle. When no range is given, all tiles are displayed during the lifetime.
253        inline void setTextureTileRange(int sTile, int tTile, int startTile, int endTile);
254
255        /// Same as above, range starts at 0 and ends at end
256        inline void setTextureTile(int sTile, int tTile, int end = -1);
257
258        inline int getStartTile() const;
259
260        inline int getEndTile() const;
261
262        /// Set the previous particle
263        inline void setPreviousParticle(int previous) { _previousParticle = previous; }
264
265        /// Get the previous particle
266        inline int getPreviousParticle() const { return _previousParticle; }
267
268        /// Set the next particle
269        inline void setNextParticle(int next) { _nextParticle = next; }
270
271        /// Get the const next particle
272        inline int getNextParticle() const { return _nextParticle; }
273
274        /// Set the depth of the particle
275        inline void setDepth(double d) { _depth = d; }
276
277        /// Get the depth of the particle
278        inline double getDepth() const { return _depth; }
279
280        /// Sorting operator
281        bool operator<(const Particle &P) const { return _depth < P._depth; }
282
283        /// Method for initializing a particles texture coords as part of a connected particle system.
284        void setUpTexCoordsAsPartOfConnectedParticleSystem(ParticleSystem* ps);
285
286    protected:
287
288        Shape _shape;
289
290        rangef _sr;
291        rangef _ar;
292        rangev4 _cr;
293
294        osg::ref_ptr<Interpolator> _si;
295        osg::ref_ptr<Interpolator> _ai;
296        osg::ref_ptr<Interpolator> _ci;
297
298        bool _mustdie;
299        double _lifeTime;
300
301        float _radius;
302        float _mass;
303        float _massinv;
304        osg::Vec3 _prev_pos;
305        osg::Vec3 _position;
306        osg::Vec3 _velocity;
307
308        osg::Vec3 _prev_angle;
309        osg::Vec3 _angle;
310        osg::Vec3 _angul_arvel;
311
312        double _t0;
313
314        float _alive;
315        float _current_size;
316        float _current_alpha;
317        osg::Vec3 _base_prop;  // [0] _alive [1] _current_size [2] _current_alpha
318        osg::Vec4 _current_color;
319
320        float _s_tile;
321        float _t_tile;
322        int _start_tile;
323        int _end_tile;
324        int _cur_tile;
325        float _s_coord;
326        float _t_coord;
327
328        // previous and next Particles are only used in ConnectedParticleSystems
329        int _previousParticle;
330        int _nextParticle;
331
332        // the depth of the particle is used only when sorting is enabled
333        double _depth;
334    };
335
336    // INLINE FUNCTIONS
337
338    inline Particle::Shape Particle::getShape() const
339    {
340        return _shape;
341    }
342
343    inline void Particle::setShape(Shape s)
344    {
345        _shape = s;
346    }
347
348    inline bool Particle::isAlive() const
349    {
350        return _alive>0.0f;
351    }
352
353    inline double Particle::getLifeTime() const
354    {
355        return _lifeTime;
356    }
357
358    inline double Particle::getAge() const
359    {
360        return _t0;
361    }
362
363    inline float Particle::getRadius() const
364    {
365        return _radius;
366    }
367
368    inline void Particle::setRadius(float r)
369    {
370        _radius = r;
371    }
372
373    inline const rangef& Particle::getSizeRange() const
374    {
375        return _sr;
376    }
377
378    inline const rangef& Particle::getAlphaRange() const
379    {
380        return _ar;
381    }
382
383    inline const rangev4& Particle::getColorRange() const
384    {
385        return _cr;
386    }
387
388    inline const Interpolator* Particle::getSizeInterpolator() const
389    {
390        return _si.get();
391    }
392
393    inline const Interpolator* Particle::getAlphaInterpolator() const
394    {
395        return _ai.get();
396    }
397
398    inline const Interpolator* Particle::getColorInterpolator() const
399    {
400        return _ci.get();
401    }
402
403    inline const osg::Vec3& Particle::getPosition() const
404    {
405        return _position;
406    }
407
408    inline const osg::Vec3& Particle::getVelocity() const
409    {
410        return _velocity;
411    }
412
413    inline const osg::Vec3& Particle::getPreviousPosition() const
414    {
415        return _prev_pos;
416    }
417
418    inline const osg::Vec3& Particle::getAngle() const
419    {
420        return _angle;
421    }
422
423    inline const osg::Vec3& Particle::getAngularVelocity() const
424    {
425        return _angul_arvel;
426    }
427
428    inline const osg::Vec3& Particle::getPreviousAngle() const
429    {
430        return _prev_angle;
431    }
432
433    inline int Particle::getTileS() const
434    {
435        return (_s_tile>0.0f) ? static_cast<int>(1.0f / _s_tile) : 1;
436    }
437
438    inline int Particle::getTileT() const
439    {
440        return (_t_tile>0.0f) ? static_cast<int>(1.0f / _t_tile) : 1;
441    }
442
443    inline void Particle::kill()
444    {
445        _mustdie = true;
446    }
447
448    inline void Particle::setLifeTime(double t)
449    {
450        _lifeTime = t;
451    }
452
453    inline void Particle::setSizeRange(const rangef& r)
454    {
455        _sr = r;
456    }
457
458    inline void Particle::setAlphaRange(const rangef& r)
459    {
460        _ar = r;
461    }
462
463    inline void Particle::setColorRange(const rangev4& r)
464    {
465        _cr = r;
466    }
467
468    inline void Particle::setSizeInterpolator(Interpolator* ri)
469    {
470        _si = ri;
471    }
472
473    inline void Particle::setAlphaInterpolator(Interpolator* ai)
474    {
475        _ai = ai;
476    }
477
478    inline void Particle::setColorInterpolator(Interpolator* ci)
479    {
480        _ci = ci;
481    }
482
483    inline void Particle::setPosition(const osg::Vec3& p)
484    {
485        _position = p;
486    }
487
488    inline void Particle::setVelocity(const osg::Vec3& v)
489    {
490        _velocity = v;
491    }
492
493    inline void Particle::addVelocity(const osg::Vec3& dv)
494    {
495        _velocity += dv;
496    }
497
498    inline void Particle::transformPositionVelocity(const osg::Matrix& xform)
499    {
500        _position = xform.preMult(_position);
501        _velocity = osg::Matrix::transform3x3(_velocity, xform);
502    }
503
504    inline void Particle::transformPositionVelocity(const osg::Matrix& xform1, const osg::Matrix& xform2, float r)
505    {
506        osg::Vec3 position1 = xform1.preMult(_position);
507        osg::Vec3 velocity1 = osg::Matrix::transform3x3(_velocity, xform1);
508        osg::Vec3 position2 = xform2.preMult(_position);
509        osg::Vec3 velocity2 = osg::Matrix::transform3x3(_velocity, xform2);
510        float one_minus_r = 1.0f-r;
511        _position = position1*r + position2*one_minus_r;
512        _velocity = velocity1*r + velocity2*one_minus_r;
513    }
514
515    inline void Particle::setAngle(const osg::Vec3& a)
516    {
517        _angle = a;
518    }
519
520    inline void Particle::setAngularVelocity(const osg::Vec3& v)
521    {
522        _angul_arvel = v;
523    }
524
525    inline void Particle::addAngularVelocity(const osg::Vec3& dv)
526    {
527        _angul_arvel += dv;
528    }
529
530    inline void Particle::transformAngleVelocity(const osg::Matrix& xform)
531    {
532        // this should be optimized!
533
534        osg::Vec3 a1 = _angle + _angul_arvel;
535
536        _angle = xform.preMult(_angle);
537        a1 = xform.preMult(a1);
538
539        _angul_arvel = a1 - _angle;
540    }
541
542    inline float Particle::getMass() const
543    {
544        return _mass;
545    }
546
547    inline float Particle::getMassInv() const
548    {
549        return _massinv;
550    }
551
552    inline void Particle::setMass(float m)
553    {
554        _mass = m;
555        _massinv = 1 / m;
556    }
557
558    inline float Particle::getCurrentSize() const
559    {
560        return _current_size;
561    }
562
563
564    inline void Particle::setTextureTile(int sTile, int tTile, int end)
565    {
566        setTextureTileRange(sTile, tTile, -1, end);
567    }
568
569    inline void Particle::setTextureTileRange(int sTile, int tTile, int startTile, int endTile)
570    {
571       _s_tile = (sTile>0) ? 1.0f / static_cast<float>(sTile) : 1.0f;
572       _t_tile = (tTile>0) ? 1.0f / static_cast<float>(tTile) : 1.0f;
573
574       if(startTile == -1)
575       {
576          _start_tile = 0;
577       }
578       else
579       {
580          _start_tile = startTile;
581       }
582
583       if(endTile == -1)
584       {
585          _end_tile = sTile * tTile;
586       }
587       else
588       {
589          _end_tile = endTile;
590       }
591    }
592
593    inline int Particle::getStartTile() const
594    {
595        return _start_tile;
596    }
597
598    inline int Particle::getEndTile() const
599    {
600        return _end_tile;
601    }
602}
603
604#endif
605
606