ParticleEmitter.cpp 30 KB

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