ParticleEmitter.cpp 29 KB

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