ParticleEmitter.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. #include "Base.h"
  2. #include "ParticleEmitter.h"
  3. #include "Game.h"
  4. #include "Node.h"
  5. #include "Scene.h"
  6. #include "Quaternion.h"
  7. #include "Properties.h"
  8. #define PARTICLE_COUNT_MAX 100
  9. #define PARTICLE_EMISSION_RATE 10
  10. #define PARTICLE_EMISSION_RATE_TIME_INTERVAL 1000.0f / (float)PARTICLE_EMISSION_RATE
  11. namespace gameplay
  12. {
  13. ParticleEmitter::ParticleEmitter(SpriteBatch* batch, unsigned int particleCountMax) :
  14. _particleCountMax(particleCountMax), _particleCount(0), _particles(NULL),
  15. _emissionRate(PARTICLE_EMISSION_RATE), _started(false), _ellipsoid(false),
  16. _sizeStartMin(1.0f), _sizeStartMax(1.0f), _sizeEndMin(1.0f), _sizeEndMax(1.0f),
  17. _energyMin(1000L), _energyMax(1000L),
  18. _colorStart(Vector4::zero()), _colorStartVar(Vector4::zero()), _colorEnd(Vector4::one()), _colorEndVar(Vector4::zero()),
  19. _position(Vector3::zero()), _positionVar(Vector3::zero()),
  20. _velocity(Vector3::zero()), _velocityVar(Vector3::one()),
  21. _acceleration(Vector3::zero()), _accelerationVar(Vector3::zero()),
  22. _rotationPerParticleSpeedMin(0.0f), _rotationPerParticleSpeedMax(0.0f),
  23. _rotationSpeedMin(0.0f), _rotationSpeedMax(0.0f),
  24. _rotationAxis(Vector3::zero()), _rotation(Matrix::identity()),
  25. _spriteBatch(batch), _spriteTextureBlending(BLEND_TRANSPARENT), _spriteTextureWidth(0), _spriteTextureHeight(0), _spriteTextureWidthRatio(0), _spriteTextureHeightRatio(0), _spriteTextureCoords(NULL),
  26. _spriteAnimated(false), _spriteLooped(false), _spriteFrameCount(1), _spriteFrameRandomOffset(0),_spriteFrameDuration(0L), _spriteFrameDurationSecs(0.0f), _spritePercentPerFrame(0.0f),
  27. _node(NULL), _orbitPosition(false), _orbitVelocity(false), _orbitAcceleration(false),
  28. _timePerEmission(PARTICLE_EMISSION_RATE_TIME_INTERVAL), _timeRunning(0)
  29. {
  30. GP_ASSERT(particleCountMax);
  31. _particles = new Particle[particleCountMax];
  32. GP_ASSERT(_spriteBatch);
  33. GP_ASSERT(_spriteBatch->getStateBlock());
  34. _spriteBatch->getStateBlock()->setDepthWrite(false);
  35. _spriteBatch->getStateBlock()->setDepthTest(true);
  36. }
  37. ParticleEmitter::~ParticleEmitter()
  38. {
  39. SAFE_DELETE(_spriteBatch);
  40. SAFE_DELETE_ARRAY(_particles);
  41. SAFE_DELETE_ARRAY(_spriteTextureCoords);
  42. }
  43. ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlending textureBlending, unsigned int particleCountMax)
  44. {
  45. Texture* texture = Texture::create(textureFile, false);
  46. if (!texture)
  47. {
  48. GP_ERROR("Failed to create texture for particle emitter.");
  49. return NULL;
  50. }
  51. GP_ASSERT(texture->getWidth());
  52. GP_ASSERT(texture->getHeight());
  53. // Use default SpriteBatch material.
  54. SpriteBatch* batch = SpriteBatch::create(texture, NULL, particleCountMax);
  55. texture->release(); // batch owns the texture.
  56. GP_ASSERT(batch);
  57. ParticleEmitter* emitter = new ParticleEmitter(batch, particleCountMax);
  58. GP_ASSERT(emitter);
  59. // By default assume only one frame which uses the entire texture.
  60. emitter->setTextureBlending(textureBlending);
  61. emitter->_spriteTextureWidth = texture->getWidth();
  62. emitter->_spriteTextureHeight = texture->getHeight();
  63. emitter->_spriteTextureWidthRatio = 1.0f / (float)texture->getWidth();
  64. emitter->_spriteTextureHeightRatio = 1.0f / (float)texture->getHeight();
  65. Rectangle texCoord((float)texture->getWidth(), (float)texture->getHeight());
  66. emitter->setSpriteFrameCoords(1, &texCoord);
  67. return emitter;
  68. }
  69. ParticleEmitter* ParticleEmitter::create(const char* url)
  70. {
  71. Properties* properties = Properties::create(url);
  72. if (!properties)
  73. {
  74. GP_ERROR("Failed to create particle emitter from file.");
  75. return NULL;
  76. }
  77. ParticleEmitter* particle = create((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
  78. SAFE_DELETE(properties);
  79. return particle;
  80. }
  81. ParticleEmitter* ParticleEmitter::create(Properties* properties)
  82. {
  83. if (!properties || strcmp(properties->getNamespace(), "particle") != 0)
  84. {
  85. GP_ERROR("Properties object must be non-null and have namespace equal to 'particle'.");
  86. return NULL;
  87. }
  88. Properties* sprite = properties->getNextNamespace();
  89. if (!sprite || strcmp(sprite->getNamespace(), "sprite") != 0)
  90. {
  91. GP_ERROR("Failed to load particle emitter: required namespace 'sprite' is missing.");
  92. return NULL;
  93. }
  94. // Load sprite properties.
  95. // Path to image file is required.
  96. std::string texturePath;
  97. if (!sprite->getPath("path", &texturePath))
  98. {
  99. GP_ERROR("Failed to load particle emitter: required image file path ('path') is missing.");
  100. return NULL;
  101. }
  102. const char* blendingString = sprite->getString("blending");
  103. TextureBlending textureBlending = getTextureBlendingFromString(blendingString);
  104. int spriteWidth = sprite->getInt("width");
  105. int spriteHeight = sprite->getInt("height");
  106. bool spriteAnimated = sprite->getBool("animated");
  107. bool spriteLooped = sprite->getBool("looped");
  108. int spriteFrameCount = sprite->getInt("frameCount");
  109. int spriteFrameRandomOffset = sprite->getInt("frameRandomOffset");
  110. float spriteFrameDuration = sprite->getFloat("frameDuration");
  111. // Emitter properties.
  112. unsigned int particleCountMax = (unsigned int)properties->getInt("particleCountMax");
  113. if (particleCountMax == 0)
  114. {
  115. // Set sensible default.
  116. particleCountMax = PARTICLE_COUNT_MAX;
  117. }
  118. unsigned int emissionRate = (unsigned int)properties->getInt("emissionRate");
  119. if (emissionRate == 0)
  120. {
  121. emissionRate = PARTICLE_EMISSION_RATE;
  122. }
  123. bool ellipsoid = properties->getBool("ellipsoid");
  124. float sizeStartMin = properties->getFloat("sizeStartMin");
  125. float sizeStartMax = properties->getFloat("sizeStartMax");
  126. float sizeEndMin = properties->getFloat("sizeEndMin");
  127. float sizeEndMax = properties->getFloat("sizeEndMax");
  128. long energyMin = properties->getLong("energyMin");
  129. long energyMax = properties->getLong("energyMax");
  130. Vector4 colorStart;
  131. Vector4 colorStartVar;
  132. Vector4 colorEnd;
  133. Vector4 colorEndVar;
  134. properties->getVector4("colorStart", &colorStart);
  135. properties->getVector4("colorStartVar", &colorStartVar);
  136. properties->getVector4("colorEnd", &colorEnd);
  137. properties->getVector4("colorEndVar", &colorEndVar);
  138. Vector3 position;
  139. Vector3 positionVar;
  140. Vector3 velocity;
  141. Vector3 velocityVar;
  142. Vector3 acceleration;
  143. Vector3 accelerationVar;
  144. Vector3 rotationAxis;
  145. Vector3 rotationAxisVar;
  146. properties->getVector3("position", &position);
  147. properties->getVector3("positionVar", &positionVar);
  148. properties->getVector3("velocity", &velocity);
  149. properties->getVector3("velocityVar", &velocityVar);
  150. properties->getVector3("acceleration", &acceleration);
  151. properties->getVector3("accelerationVar", &accelerationVar);
  152. float rotationPerParticleSpeedMin = properties->getFloat("rotationPerParticleSpeedMin");
  153. float rotationPerParticleSpeedMax = properties->getFloat("rotationPerParticleSpeedMax");
  154. float rotationSpeedMin = properties->getFloat("rotationSpeedMin");
  155. float rotationSpeedMax = properties->getFloat("rotationSpeedMax");
  156. properties->getVector3("rotationAxis", &rotationAxis);
  157. properties->getVector3("rotationAxisVar", &rotationAxisVar);
  158. bool orbitPosition = properties->getBool("orbitPosition");
  159. bool orbitVelocity = properties->getBool("orbitVelocity");
  160. bool orbitAcceleration = properties->getBool("orbitAcceleration");
  161. // Apply all properties to a newly created ParticleEmitter.
  162. ParticleEmitter* emitter = ParticleEmitter::create(texturePath.c_str(), textureBlending, particleCountMax);
  163. if (!emitter)
  164. {
  165. GP_ERROR("Failed to create particle emitter.");
  166. return NULL;
  167. }
  168. emitter->setEmissionRate(emissionRate);
  169. emitter->setEllipsoid(ellipsoid);
  170. emitter->setSize(sizeStartMin, sizeStartMax, sizeEndMin, sizeEndMax);
  171. emitter->setEnergy(energyMin, energyMax);
  172. emitter->setColor(colorStart, colorStartVar, colorEnd, colorEndVar);
  173. emitter->setPosition(position, positionVar);
  174. emitter->setVelocity(velocity, velocityVar);
  175. emitter->setAcceleration(acceleration, accelerationVar);
  176. emitter->setRotationPerParticle(rotationPerParticleSpeedMin, rotationPerParticleSpeedMax);
  177. emitter->setRotation(rotationSpeedMin, rotationSpeedMax, rotationAxis, rotationAxisVar);
  178. emitter->setSpriteAnimated(spriteAnimated);
  179. emitter->setSpriteLooped(spriteLooped);
  180. emitter->setSpriteFrameRandomOffset(spriteFrameRandomOffset);
  181. emitter->setSpriteFrameDuration(spriteFrameDuration);
  182. emitter->setSpriteFrameCoords(spriteFrameCount, spriteWidth, spriteHeight);
  183. emitter->setOrbit(orbitPosition, orbitVelocity, orbitAcceleration);
  184. return emitter;
  185. }
  186. unsigned int ParticleEmitter::getEmissionRate() const
  187. {
  188. return _emissionRate;
  189. }
  190. void ParticleEmitter::setEmissionRate(unsigned int rate)
  191. {
  192. GP_ASSERT(rate);
  193. _emissionRate = rate;
  194. _timePerEmission = 1000.0f / (float)_emissionRate;
  195. }
  196. void ParticleEmitter::start()
  197. {
  198. _started = true;
  199. }
  200. void ParticleEmitter::stop()
  201. {
  202. _started = false;
  203. }
  204. bool ParticleEmitter::isStarted() const
  205. {
  206. return _started;
  207. }
  208. bool ParticleEmitter::isActive() const
  209. {
  210. if (_started)
  211. return true;
  212. if (!_node)
  213. return false;
  214. GP_ASSERT(_particles);
  215. bool active = false;
  216. for (unsigned int i = 0; i < _particleCount; i++)
  217. {
  218. if (_particles[i]._energy > 0)
  219. {
  220. active = true;
  221. break;
  222. }
  223. }
  224. return active;
  225. }
  226. void ParticleEmitter::emitOnce(unsigned int particleCount)
  227. {
  228. GP_ASSERT(_node);
  229. GP_ASSERT(_particles);
  230. // Limit particleCount so as not to go over _particleCountMax.
  231. if (particleCount + _particleCount > _particleCountMax)
  232. {
  233. particleCount = _particleCountMax - _particleCount;
  234. }
  235. Vector3 translation;
  236. Matrix world = _node->getWorldMatrix();
  237. world.getTranslation(&translation);
  238. // Take translation out of world matrix so it can be used to rotate orbiting properties.
  239. world.m[12] = 0.0f;
  240. world.m[13] = 0.0f;
  241. world.m[14] = 0.0f;
  242. // Emit the new particles.
  243. for (unsigned int i = 0; i < particleCount; i++)
  244. {
  245. Particle* p = &_particles[_particleCount];
  246. p->_visible = true;
  247. generateColor(_colorStart, _colorStartVar, &p->_colorStart);
  248. generateColor(_colorEnd, _colorEndVar, &p->_colorEnd);
  249. p->_color.set(p->_colorStart);
  250. p->_energy = p->_energyStart = generateScalar(_energyMin, _energyMax);
  251. p->_size = p->_sizeStart = generateScalar(_sizeStartMin, _sizeStartMax);
  252. p->_sizeEnd = generateScalar(_sizeEndMin, _sizeEndMax);
  253. p->_rotationPerParticleSpeed = generateScalar(_rotationPerParticleSpeedMin, _rotationPerParticleSpeedMax);
  254. p->_angle = generateScalar(0.0f, p->_rotationPerParticleSpeed);
  255. p->_rotationSpeed = generateScalar(_rotationSpeedMin, _rotationSpeedMax);
  256. // Only initial position can be generated within an ellipsoidal domain.
  257. generateVector(_position, _positionVar, &p->_position, _ellipsoid);
  258. generateVector(_velocity, _velocityVar, &p->_velocity, false);
  259. generateVector(_acceleration, _accelerationVar, &p->_acceleration, false);
  260. generateVector(_rotationAxis, _rotationAxisVar, &p->_rotationAxis, false);
  261. // Initial position, velocity and acceleration can all be relative to the emitter's transform.
  262. // Rotate specified properties by the node's rotation.
  263. if (_orbitPosition)
  264. {
  265. world.transformPoint(p->_position, &p->_position);
  266. }
  267. if (_orbitVelocity)
  268. {
  269. world.transformPoint(p->_velocity, &p->_velocity);
  270. }
  271. if (_orbitAcceleration)
  272. {
  273. world.transformPoint(p->_acceleration, &p->_acceleration);
  274. }
  275. // The rotation axis always orbits the node.
  276. if (p->_rotationSpeed != 0.0f && !p->_rotationAxis.isZero())
  277. {
  278. world.transformPoint(p->_rotationAxis, &p->_rotationAxis);
  279. }
  280. // Translate position relative to the node's world space.
  281. p->_position.add(translation);
  282. // Initial sprite frame.
  283. if (_spriteFrameRandomOffset > 0)
  284. {
  285. p->_frame = rand() % _spriteFrameRandomOffset;
  286. }
  287. else
  288. {
  289. p->_frame = 0;
  290. }
  291. p->_timeOnCurrentFrame = 0.0f;
  292. ++_particleCount;
  293. }
  294. }
  295. unsigned int ParticleEmitter::getParticlesCount() const
  296. {
  297. return _particleCount;
  298. }
  299. void ParticleEmitter::setEllipsoid(bool ellipsoid)
  300. {
  301. _ellipsoid = ellipsoid;
  302. }
  303. bool ParticleEmitter::isEllipsoid() const
  304. {
  305. return _ellipsoid;
  306. }
  307. void ParticleEmitter::setSize(float startMin, float startMax, float endMin, float endMax)
  308. {
  309. _sizeStartMin = startMin;
  310. _sizeStartMax = startMax;
  311. _sizeEndMin = endMin;
  312. _sizeEndMax = endMax;
  313. }
  314. float ParticleEmitter::getSizeStartMin() const
  315. {
  316. return _sizeStartMin;
  317. }
  318. float ParticleEmitter::getSizeStartMax() const
  319. {
  320. return _sizeStartMax;
  321. }
  322. float ParticleEmitter::getSizeEndMin() const
  323. {
  324. return _sizeEndMin;
  325. }
  326. float ParticleEmitter::getSizeEndMax() const
  327. {
  328. return _sizeEndMax;
  329. }
  330. void ParticleEmitter::setEnergy(long energyMin, long energyMax)
  331. {
  332. _energyMin = energyMin;
  333. _energyMax = energyMax;
  334. }
  335. long ParticleEmitter::getEnergyMin() const
  336. {
  337. return _energyMin;
  338. }
  339. long ParticleEmitter::getEnergyMax() const
  340. {
  341. return _energyMax;
  342. }
  343. void ParticleEmitter::setColor(const Vector4& startColor, const Vector4& startColorVar, const Vector4& endColor, const Vector4& endColorVar)
  344. {
  345. _colorStart.set(startColor);
  346. _colorStartVar.set(startColorVar);
  347. _colorEnd.set(endColor);
  348. _colorEndVar.set(endColorVar);
  349. }
  350. const Vector4& ParticleEmitter::getColorStart() const
  351. {
  352. return _colorStart;
  353. }
  354. const Vector4& ParticleEmitter::getColorStartVariance() const
  355. {
  356. return _colorStartVar;
  357. }
  358. const Vector4& ParticleEmitter::getColorEnd() const
  359. {
  360. return _colorEnd;
  361. }
  362. const Vector4& ParticleEmitter::getColorEndVariance() const
  363. {
  364. return _colorEndVar;
  365. }
  366. void ParticleEmitter::setPosition(const Vector3& position, const Vector3& positionVar)
  367. {
  368. _position.set(position);
  369. _positionVar.set(positionVar);
  370. }
  371. const Vector3& ParticleEmitter::getPosition() const
  372. {
  373. return _position;
  374. }
  375. const Vector3& ParticleEmitter::getPositionVariance() const
  376. {
  377. return _positionVar;
  378. }
  379. const Vector3& ParticleEmitter::getVelocity() const
  380. {
  381. return _velocity;
  382. }
  383. const Vector3& ParticleEmitter::getVelocityVariance() const
  384. {
  385. return _velocityVar;
  386. }
  387. void ParticleEmitter::setVelocity(const Vector3& velocity, const Vector3& velocityVar)
  388. {
  389. _velocity.set(velocity);
  390. _velocityVar.set(velocityVar);
  391. }
  392. const Vector3& ParticleEmitter::getAcceleration() const
  393. {
  394. return _acceleration;
  395. }
  396. const Vector3& ParticleEmitter::getAccelerationVariance() const
  397. {
  398. return _accelerationVar;
  399. }
  400. void ParticleEmitter::setAcceleration(const Vector3& acceleration, const Vector3& accelerationVar)
  401. {
  402. _acceleration.set(acceleration);
  403. _accelerationVar.set(accelerationVar);
  404. }
  405. void ParticleEmitter::setRotationPerParticle(float speedMin, float speedMax)
  406. {
  407. _rotationPerParticleSpeedMin = speedMin;
  408. _rotationPerParticleSpeedMax = speedMax;
  409. }
  410. float ParticleEmitter::getRotationPerParticleSpeedMin() const
  411. {
  412. return _rotationPerParticleSpeedMin;
  413. }
  414. float ParticleEmitter::getRotationPerParticleSpeedMax() const
  415. {
  416. return _rotationPerParticleSpeedMax;
  417. }
  418. void ParticleEmitter::setRotation(float speedMin, float speedMax, const Vector3& axis, const Vector3& axisVariance)
  419. {
  420. _rotationSpeedMin = speedMin;
  421. _rotationSpeedMax = speedMax;
  422. _rotationAxis.set(axis);
  423. _rotationAxisVar.set(axisVariance);
  424. }
  425. float ParticleEmitter::getRotationSpeedMin() const
  426. {
  427. return _rotationSpeedMin;
  428. }
  429. float ParticleEmitter::getRotationSpeedMax() const
  430. {
  431. return _rotationSpeedMax;
  432. }
  433. const Vector3& ParticleEmitter::getRotationAxis() const
  434. {
  435. return _rotationAxis;
  436. }
  437. const Vector3& ParticleEmitter::getRotationAxisVariance() const
  438. {
  439. return _rotationAxisVar;
  440. }
  441. void ParticleEmitter::setTextureBlending(TextureBlending textureBlending)
  442. {
  443. GP_ASSERT(_spriteBatch);
  444. GP_ASSERT(_spriteBatch->getStateBlock());
  445. switch (textureBlending)
  446. {
  447. case BLEND_OPAQUE:
  448. _spriteBatch->getStateBlock()->setBlend(false);
  449. break;
  450. case BLEND_TRANSPARENT:
  451. _spriteBatch->getStateBlock()->setBlend(true);
  452. _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  453. _spriteBatch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
  454. break;
  455. case BLEND_ADDITIVE:
  456. _spriteBatch->getStateBlock()->setBlend(true);
  457. _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
  458. _spriteBatch->getStateBlock()->setBlendDst(RenderState::BLEND_ONE);
  459. break;
  460. case BLEND_MULTIPLIED:
  461. _spriteBatch->getStateBlock()->setBlend(true);
  462. _spriteBatch->getStateBlock()->setBlendSrc(RenderState::BLEND_ZERO);
  463. _spriteBatch->getStateBlock()->setBlendDst(RenderState::BLEND_SRC_COLOR);
  464. break;
  465. default:
  466. GP_ERROR("Unsupported texture blending mode (%d).", textureBlending);
  467. break;
  468. }
  469. }
  470. void ParticleEmitter::setSpriteAnimated(bool animated)
  471. {
  472. _spriteAnimated = animated;
  473. }
  474. bool ParticleEmitter::isSpriteAnimated() const
  475. {
  476. return _spriteAnimated;
  477. }
  478. void ParticleEmitter::setSpriteLooped(bool looped)
  479. {
  480. _spriteLooped = looped;
  481. }
  482. bool ParticleEmitter::isSpriteLooped() const
  483. {
  484. return _spriteLooped;
  485. }
  486. void ParticleEmitter::setSpriteFrameRandomOffset(int maxOffset)
  487. {
  488. _spriteFrameRandomOffset = maxOffset;
  489. }
  490. int ParticleEmitter::getSpriteFrameRandomOffset() const
  491. {
  492. return _spriteFrameRandomOffset;
  493. }
  494. void ParticleEmitter::setSpriteFrameDuration(long duration)
  495. {
  496. _spriteFrameDuration = duration;
  497. _spriteFrameDurationSecs = (float)duration / 1000.0f;
  498. }
  499. long ParticleEmitter::getSpriteFrameDuration() const
  500. {
  501. return _spriteFrameDuration;
  502. }
  503. void ParticleEmitter::setSpriteTexCoords(unsigned int frameCount, float* texCoords)
  504. {
  505. GP_ASSERT(frameCount);
  506. GP_ASSERT(texCoords);
  507. _spriteFrameCount = frameCount;
  508. _spritePercentPerFrame = 1.0f / (float)frameCount;
  509. SAFE_DELETE_ARRAY(_spriteTextureCoords);
  510. _spriteTextureCoords = new float[frameCount * 4];
  511. memcpy(_spriteTextureCoords, texCoords, frameCount * 4 * sizeof(float));
  512. }
  513. void ParticleEmitter::setSpriteFrameCoords(unsigned int frameCount, Rectangle* frameCoords)
  514. {
  515. GP_ASSERT(frameCount);
  516. GP_ASSERT(frameCoords);
  517. _spriteFrameCount = frameCount;
  518. _spritePercentPerFrame = 1.0f / (float)frameCount;
  519. SAFE_DELETE_ARRAY(_spriteTextureCoords);
  520. _spriteTextureCoords = new float[frameCount * 4];
  521. // Pre-compute texture coordinates from rects.
  522. for (unsigned int i = 0; i < frameCount; i++)
  523. {
  524. _spriteTextureCoords[i*4] = _spriteTextureWidthRatio * frameCoords[i].x;
  525. _spriteTextureCoords[i*4 + 1] = 1.0f - _spriteTextureHeightRatio * frameCoords[i].y;
  526. _spriteTextureCoords[i*4 + 2] = _spriteTextureCoords[i*4] + _spriteTextureWidthRatio * frameCoords[i].width;
  527. _spriteTextureCoords[i*4 + 3] = _spriteTextureCoords[i*4 + 1] - _spriteTextureHeightRatio * frameCoords[i].height;
  528. }
  529. }
  530. void ParticleEmitter::setSpriteFrameCoords(unsigned int frameCount, int width, int height)
  531. {
  532. GP_ASSERT(width);
  533. GP_ASSERT(height);
  534. int x;
  535. int y;
  536. Rectangle* frameCoords = new Rectangle[frameCount];
  537. unsigned int cols = _spriteTextureWidth / width;
  538. unsigned int rows = _spriteTextureHeight / height;
  539. unsigned int n = 0;
  540. for (unsigned int i = 0; i < rows; ++i)
  541. {
  542. y = i * height;
  543. for (unsigned int j = 0; j < cols; ++j)
  544. {
  545. x = j * width;
  546. frameCoords[i*cols + j] = Rectangle(x, y, width, height);
  547. if (++n == frameCount)
  548. {
  549. break;
  550. }
  551. }
  552. if (n == frameCount)
  553. {
  554. break;
  555. }
  556. }
  557. setSpriteFrameCoords(frameCount, frameCoords);
  558. SAFE_DELETE_ARRAY(frameCoords);
  559. }
  560. Node* ParticleEmitter::getNode() const
  561. {
  562. return _node;
  563. }
  564. void ParticleEmitter::setNode(Node* node)
  565. {
  566. // Connect the new node.
  567. _node = node;
  568. }
  569. void ParticleEmitter::setOrbit(bool orbitPosition, bool orbitVelocity, bool orbitAcceleration)
  570. {
  571. _orbitPosition = orbitPosition;
  572. _orbitVelocity = orbitVelocity;
  573. _orbitAcceleration = orbitAcceleration;
  574. }
  575. long ParticleEmitter::generateScalar(long min, long max)
  576. {
  577. // Note: this is not a very good RNG, but it should be suitable for our purposes.
  578. long r = 0;
  579. for (unsigned int i = 0; i < sizeof(long)/sizeof(int); i++)
  580. {
  581. r = r << 8; // sizeof(int) * CHAR_BITS
  582. r |= rand();
  583. }
  584. // Now we have a random long between 0 and MAX_LONG. We need to clamp it between min and max.
  585. r %= max - min;
  586. r += min;
  587. return r;
  588. }
  589. float ParticleEmitter::generateScalar(float min, float max)
  590. {
  591. return min + (max - min) * MATH_RANDOM_0_1();
  592. }
  593. void ParticleEmitter::generateVectorInRect(const Vector3& base, const Vector3& variance, Vector3* dst)
  594. {
  595. GP_ASSERT(dst);
  596. // Scale each component of the variance vector by a random float
  597. // between -1 and 1, then add this to the corresponding base component.
  598. dst->x = base.x + variance.x * MATH_RANDOM_MINUS1_1();
  599. dst->y = base.y + variance.y * MATH_RANDOM_MINUS1_1();
  600. dst->z = base.z + variance.z * MATH_RANDOM_MINUS1_1();
  601. }
  602. void ParticleEmitter::generateVectorInEllipsoid(const Vector3& center, const Vector3& scale, Vector3* dst)
  603. {
  604. GP_ASSERT(dst);
  605. // Generate a point within a unit cube, then reject if the point is not in a unit sphere.
  606. do
  607. {
  608. dst->x = MATH_RANDOM_MINUS1_1();
  609. dst->y = MATH_RANDOM_MINUS1_1();
  610. dst->z = MATH_RANDOM_MINUS1_1();
  611. } while (dst->length() > 1.0f);
  612. // Scale this point by the scaling vector.
  613. dst->x *= scale.x;
  614. dst->y *= scale.y;
  615. dst->z *= scale.z;
  616. // Translate by the center point.
  617. dst->add(center);
  618. }
  619. void ParticleEmitter::generateVector(const Vector3& base, const Vector3& variance, Vector3* dst, bool ellipsoid)
  620. {
  621. if (ellipsoid)
  622. {
  623. generateVectorInEllipsoid(base, variance, dst);
  624. }
  625. else
  626. {
  627. generateVectorInRect(base, variance, dst);
  628. }
  629. }
  630. void ParticleEmitter::generateColor(const Vector4& base, const Vector4& variance, Vector4* dst)
  631. {
  632. GP_ASSERT(dst);
  633. // Scale each component of the variance color by a random float
  634. // between -1 and 1, then add this to the corresponding base component.
  635. dst->x = base.x + variance.x * MATH_RANDOM_MINUS1_1();
  636. dst->y = base.y + variance.y * MATH_RANDOM_MINUS1_1();
  637. dst->z = base.z + variance.z * MATH_RANDOM_MINUS1_1();
  638. dst->w = base.w + variance.w * MATH_RANDOM_MINUS1_1();
  639. }
  640. ParticleEmitter::TextureBlending ParticleEmitter::getTextureBlendingFromString(const char* str)
  641. {
  642. GP_ASSERT(str);
  643. if (strcmp(str, "BLEND_OPAQUE") == 0 || strcmp(str, "OPAQUE") == 0)
  644. {
  645. return BLEND_OPAQUE;
  646. }
  647. else if (strcmp(str, "BLEND_TRANSPARENT") == 0 || strcmp(str, "TRANSPARENT") == 0)
  648. {
  649. return BLEND_TRANSPARENT;
  650. }
  651. else if (strcmp(str, "BLEND_ADDITIVE") == 0 || strcmp(str, "ADDITIVE") == 0)
  652. {
  653. return BLEND_ADDITIVE;
  654. }
  655. else if (strcmp(str, "BLEND_MULTIPLIED") == 0 || strcmp(str, "MULTIPLIED") == 0)
  656. {
  657. return BLEND_MULTIPLIED;
  658. }
  659. else
  660. {
  661. return BLEND_TRANSPARENT;
  662. }
  663. }
  664. void ParticleEmitter::update(float elapsedTime)
  665. {
  666. if (!isActive())
  667. {
  668. return;
  669. }
  670. // Calculate the time passed since last update.
  671. float elapsedSecs = elapsedTime * 0.001f;
  672. if (_started && _emissionRate)
  673. {
  674. // Calculate how much time has passed since we last emitted particles.
  675. _timeRunning += elapsedTime;
  676. // How many particles should we emit this frame?
  677. GP_ASSERT(_timePerEmission);
  678. unsigned int emitCount = (unsigned int)(_timeRunning / _timePerEmission);
  679. if (emitCount)
  680. {
  681. if ((int)_timePerEmission > 0)
  682. {
  683. _timeRunning = fmod(_timeRunning, (double)_timePerEmission);
  684. }
  685. emitOnce(emitCount);
  686. }
  687. }
  688. GP_ASSERT(_node && _node->getScene() && _node->getScene()->getActiveCamera());
  689. const Frustum& frustum = _node->getScene()->getActiveCamera()->getFrustum();
  690. // Now update all currently living particles.
  691. GP_ASSERT(_particles);
  692. for (unsigned int particlesIndex = 0; particlesIndex < _particleCount; ++particlesIndex)
  693. {
  694. Particle* p = &_particles[particlesIndex];
  695. p->_energy -= elapsedTime;
  696. if (p->_energy > 0L)
  697. {
  698. if (p->_rotationSpeed != 0.0f && !p->_rotationAxis.isZero())
  699. {
  700. Matrix::createRotation(p->_rotationAxis, p->_rotationSpeed * elapsedSecs, &_rotation);
  701. _rotation.transformPoint(p->_velocity, &p->_velocity);
  702. _rotation.transformPoint(p->_acceleration, &p->_acceleration);
  703. }
  704. // Particle is still alive.
  705. p->_velocity.x += p->_acceleration.x * elapsedSecs;
  706. p->_velocity.y += p->_acceleration.y * elapsedSecs;
  707. p->_velocity.z += p->_acceleration.z * elapsedSecs;
  708. p->_position.x += p->_velocity.x * elapsedSecs;
  709. p->_position.y += p->_velocity.y * elapsedSecs;
  710. p->_position.z += p->_velocity.z * elapsedSecs;
  711. if (!frustum.intersects(p->_position))
  712. {
  713. p->_visible = false;
  714. continue;
  715. }
  716. p->_angle += p->_rotationPerParticleSpeed * elapsedSecs;
  717. // Simple linear interpolation of color and size.
  718. float percent = 1.0f - ((float)p->_energy / (float)p->_energyStart);
  719. p->_color.x = p->_colorStart.x + (p->_colorEnd.x - p->_colorStart.x) * percent;
  720. p->_color.y = p->_colorStart.y + (p->_colorEnd.y - p->_colorStart.y) * percent;
  721. p->_color.z = p->_colorStart.z + (p->_colorEnd.z - p->_colorStart.z) * percent;
  722. p->_color.w = p->_colorStart.w + (p->_colorEnd.w - p->_colorStart.w) * percent;
  723. p->_size = p->_sizeStart + (p->_sizeEnd - p->_sizeStart) * percent;
  724. // Handle sprite animations.
  725. if (_spriteAnimated)
  726. {
  727. if (!_spriteLooped)
  728. {
  729. // The last frame should finish exactly when the particle dies.
  730. float percentSpent = 0.0f;
  731. for (unsigned int i = 0; i < p->_frame; i++)
  732. {
  733. percentSpent += _spritePercentPerFrame;
  734. }
  735. p->_timeOnCurrentFrame = percent - percentSpent;
  736. if (p->_frame < _spriteFrameCount - 1 &&
  737. p->_timeOnCurrentFrame >= _spritePercentPerFrame)
  738. {
  739. ++p->_frame;
  740. }
  741. }
  742. else
  743. {
  744. // _spriteFrameDurationSecs is an absolute time measured in seconds,
  745. // and the animation repeats indefinitely.
  746. p->_timeOnCurrentFrame += elapsedSecs;
  747. if (p->_timeOnCurrentFrame >= _spriteFrameDurationSecs)
  748. {
  749. p->_timeOnCurrentFrame -= _spriteFrameDurationSecs;
  750. ++p->_frame;
  751. if (p->_frame == _spriteFrameCount)
  752. {
  753. p->_frame = 0;
  754. }
  755. }
  756. }
  757. }
  758. }
  759. else
  760. {
  761. // Particle is dead. Move the particle furthest from the start of the array
  762. // down to take its place, and re-use the slot at the end of the list of living particles.
  763. if (particlesIndex != _particleCount - 1)
  764. {
  765. _particles[particlesIndex] = _particles[_particleCount - 1];
  766. }
  767. --_particleCount;
  768. }
  769. }
  770. }
  771. void ParticleEmitter::draw()
  772. {
  773. if (!isActive())
  774. {
  775. return;
  776. }
  777. if (_particleCount > 0)
  778. {
  779. GP_ASSERT(_spriteBatch);
  780. GP_ASSERT(_particles);
  781. GP_ASSERT(_spriteTextureCoords);
  782. // Set our node's view projection matrix to this emitter's effect.
  783. if (_node)
  784. {
  785. _spriteBatch->setProjectionMatrix(_node->getViewProjectionMatrix());
  786. }
  787. // Begin sprite batch drawing
  788. _spriteBatch->start();
  789. // 2D Rotation.
  790. static const Vector2 pivot(0.5f, 0.5f);
  791. // 3D Rotation so that particles always face the camera.
  792. GP_ASSERT(_node && _node->getScene() && _node->getScene()->getActiveCamera() && _node->getScene()->getActiveCamera()->getNode());
  793. const Matrix& cameraWorldMatrix = _node->getScene()->getActiveCamera()->getNode()->getWorldMatrix();
  794. Vector3 right;
  795. cameraWorldMatrix.getRightVector(&right);
  796. Vector3 up;
  797. cameraWorldMatrix.getUpVector(&up);
  798. for (unsigned int i = 0; i < _particleCount; i++)
  799. {
  800. Particle* p = &_particles[i];
  801. if (p->_visible)
  802. {
  803. _spriteBatch->draw(p->_position, right, up, p->_size, p->_size,
  804. _spriteTextureCoords[p->_frame * 4], _spriteTextureCoords[p->_frame * 4 + 1], _spriteTextureCoords[p->_frame * 4 + 2], _spriteTextureCoords[p->_frame * 4 + 3],
  805. p->_color, pivot, p->_angle);
  806. }
  807. }
  808. // Render.
  809. _spriteBatch->finish();
  810. }
  811. }
  812. }