ParticleEmitter.cpp 29 KB

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