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