ParticleSystem.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. /**
  2. * Copyright (c) 2006-2014 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. //LOVE
  21. #include "common/config.h"
  22. #include "ParticleSystem.h"
  23. #include "common/math.h"
  24. #include "modules/math/RandomGenerator.h"
  25. #include "OpenGL.h"
  26. // STD
  27. #include <algorithm>
  28. #include <cmath>
  29. #include <cstdlib>
  30. namespace love
  31. {
  32. namespace graphics
  33. {
  34. namespace opengl
  35. {
  36. namespace
  37. {
  38. love::math::RandomGenerator rng;
  39. Colorf colorToFloat(const Color &c)
  40. {
  41. return Colorf((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, (float)c.a/255.0f);
  42. }
  43. float calculate_variation(float inner, float outer, float var)
  44. {
  45. float low = inner - (outer/2.0f)*var;
  46. float high = inner + (outer/2.0f)*var;
  47. float r = (float) rng.random();
  48. return low*(1-r)+high*r;
  49. }
  50. } // anonymous namespace
  51. ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
  52. : pMem(nullptr)
  53. , pFree(nullptr)
  54. , pHead(nullptr)
  55. , pTail(nullptr)
  56. , particleVerts(nullptr)
  57. , texture(texture)
  58. , active(true)
  59. , insertMode(INSERT_MODE_TOP)
  60. , maxParticles(0)
  61. , activeParticles(0)
  62. , emissionRate(0)
  63. , emitCounter(0)
  64. , areaSpreadDistribution(DISTRIBUTION_NONE)
  65. , lifetime(-1)
  66. , life(0)
  67. , particleLifeMin(0)
  68. , particleLifeMax(0)
  69. , direction(0)
  70. , spread(0)
  71. , speedMin(0)
  72. , speedMax(0)
  73. , linearAccelerationMin(0, 0)
  74. , linearAccelerationMax(0, 0)
  75. , radialAccelerationMin(0)
  76. , radialAccelerationMax(0)
  77. , tangentialAccelerationMin(0)
  78. , tangentialAccelerationMax(0)
  79. , sizeVariation(0)
  80. , rotationMin(0)
  81. , rotationMax(0)
  82. , spinStart(0)
  83. , spinEnd(0)
  84. , spinVariation(0)
  85. , offsetX(float(texture->getWidth())*0.5f)
  86. , offsetY(float(texture->getHeight())*0.5f)
  87. {
  88. if (size == 0 || size > MAX_PARTICLES)
  89. throw love::Exception("Invalid ParticleSystem size.");
  90. sizes.push_back(1.0f);
  91. colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
  92. setBufferSize(size);
  93. texture->retain();
  94. }
  95. ParticleSystem::ParticleSystem(const ParticleSystem &p)
  96. : pMem(nullptr)
  97. , pFree(nullptr)
  98. , pHead(nullptr)
  99. , pTail(nullptr)
  100. , particleVerts(nullptr)
  101. , texture(p.texture)
  102. , active(p.active)
  103. , insertMode(p.insertMode)
  104. , maxParticles(p.maxParticles)
  105. , activeParticles(0)
  106. , emissionRate(p.emissionRate)
  107. , emitCounter(0.0f)
  108. , position(p.position)
  109. , prevPosition(p.prevPosition)
  110. , areaSpreadDistribution(p.areaSpreadDistribution)
  111. , areaSpread(p.areaSpread)
  112. , lifetime(p.lifetime)
  113. , life(p.lifetime) // Initialize with the maximum life time.
  114. , particleLifeMin(p.particleLifeMin)
  115. , particleLifeMax(p.particleLifeMax)
  116. , direction(p.direction)
  117. , spread(p.spread)
  118. , speedMin(p.speedMin)
  119. , speedMax(p.speedMax)
  120. , linearAccelerationMin(p.linearAccelerationMin)
  121. , linearAccelerationMax(p.linearAccelerationMax)
  122. , radialAccelerationMin(p.radialAccelerationMin)
  123. , radialAccelerationMax(p.radialAccelerationMax)
  124. , tangentialAccelerationMin(p.tangentialAccelerationMin)
  125. , tangentialAccelerationMax(p.tangentialAccelerationMax)
  126. , sizes(p.sizes)
  127. , sizeVariation(p.sizeVariation)
  128. , rotationMin(p.rotationMin)
  129. , rotationMax(p.rotationMax)
  130. , spinStart(p.spinStart)
  131. , spinEnd(p.spinEnd)
  132. , spinVariation(p.spinVariation)
  133. , offsetX(p.offsetX)
  134. , offsetY(p.offsetY)
  135. , colors(p.colors)
  136. {
  137. setBufferSize(maxParticles);
  138. if (texture != nullptr)
  139. texture->retain();
  140. }
  141. ParticleSystem::~ParticleSystem()
  142. {
  143. if (texture != nullptr)
  144. texture->release();
  145. deleteBuffers();
  146. }
  147. ParticleSystem *ParticleSystem::clone()
  148. {
  149. return new ParticleSystem(*this);
  150. }
  151. void ParticleSystem::createBuffers(size_t size)
  152. {
  153. try
  154. {
  155. pFree = pMem = new particle[size];
  156. particleVerts = new love::Vertex[size * 4];
  157. maxParticles = (uint32) size;
  158. }
  159. catch (std::bad_alloc &)
  160. {
  161. deleteBuffers();
  162. throw love::Exception("Out of memory");
  163. }
  164. }
  165. void ParticleSystem::deleteBuffers()
  166. {
  167. // Clean up for great gracefulness!
  168. delete[] pMem;
  169. delete[] particleVerts;
  170. pMem = nullptr;
  171. particleVerts = nullptr;
  172. maxParticles = 0;
  173. activeParticles = 0;
  174. }
  175. void ParticleSystem::setBufferSize(uint32 size)
  176. {
  177. if (size == 0 || size > MAX_PARTICLES)
  178. throw love::Exception("Invalid buffer size");
  179. deleteBuffers();
  180. createBuffers(size);
  181. reset();
  182. }
  183. uint32 ParticleSystem::getBufferSize() const
  184. {
  185. return maxParticles;
  186. }
  187. void ParticleSystem::addParticle(float t)
  188. {
  189. if (isFull())
  190. return;
  191. // Gets a free particle and updates the allocation pointer.
  192. particle *p = pFree++;
  193. initParticle(p, t);
  194. switch (insertMode)
  195. {
  196. default:
  197. case INSERT_MODE_TOP:
  198. insertTop(p);
  199. break;
  200. case INSERT_MODE_BOTTOM:
  201. insertBottom(p);
  202. break;
  203. case INSERT_MODE_RANDOM:
  204. insertRandom(p);
  205. break;
  206. }
  207. activeParticles++;
  208. }
  209. void ParticleSystem::initParticle(particle *p, float t)
  210. {
  211. float min,max;
  212. // Linearly interpolate between the previous and current emitter position.
  213. love::Vector pos = prevPosition + (position - prevPosition) * t;
  214. min = particleLifeMin;
  215. max = particleLifeMax;
  216. if (min == max)
  217. p->life = min;
  218. else
  219. p->life = (float) rng.random(min, max);
  220. p->lifetime = p->life;
  221. p->position[0] = pos.x;
  222. p->position[1] = pos.y;
  223. switch (areaSpreadDistribution)
  224. {
  225. case DISTRIBUTION_UNIFORM:
  226. p->position[0] += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
  227. p->position[1] += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
  228. break;
  229. case DISTRIBUTION_NORMAL:
  230. p->position[0] += (float) rng.randomNormal(areaSpread.getX());
  231. p->position[1] += (float) rng.randomNormal(areaSpread.getY());
  232. break;
  233. case DISTRIBUTION_NONE:
  234. default:
  235. break;
  236. }
  237. min = direction - spread/2.0f;
  238. max = direction + spread/2.0f;
  239. p->direction = (float) rng.random(min, max);
  240. p->origin = pos;
  241. min = speedMin;
  242. max = speedMax;
  243. float speed = (float) rng.random(min, max);
  244. p->speed = love::Vector(cosf(p->direction), sinf(p->direction));
  245. p->speed *= speed;
  246. p->linearAcceleration.x = (float) rng.random(linearAccelerationMin.x, linearAccelerationMax.x);
  247. p->linearAcceleration.y = (float) rng.random(linearAccelerationMin.y, linearAccelerationMax.y);
  248. min = radialAccelerationMin;
  249. max = radialAccelerationMax;
  250. p->radialAcceleration = (float) rng.random(min, max);
  251. min = tangentialAccelerationMin;
  252. max = tangentialAccelerationMax;
  253. p->tangentialAcceleration = (float) rng.random(min, max);
  254. p->sizeOffset = (float) rng.random(sizeVariation); // time offset for size change
  255. p->sizeIntervalSize = (1.0f - (float) rng.random(sizeVariation)) - p->sizeOffset;
  256. p->size = sizes[(size_t)(p->sizeOffset - .5f) * (sizes.size() - 1)];
  257. min = rotationMin;
  258. max = rotationMax;
  259. p->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
  260. p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
  261. p->rotation = (float) rng.random(min, max);
  262. p->color = colors[0];
  263. }
  264. void ParticleSystem::insertTop(particle *p)
  265. {
  266. if (pHead == nullptr)
  267. {
  268. pHead = p;
  269. p->prev = nullptr;
  270. }
  271. else
  272. {
  273. pTail->next = p;
  274. p->prev = pTail;
  275. }
  276. p->next = nullptr;
  277. pTail = p;
  278. }
  279. void ParticleSystem::insertBottom(particle *p)
  280. {
  281. if (pTail == nullptr)
  282. {
  283. pTail = p;
  284. p->next = nullptr;
  285. }
  286. else
  287. {
  288. pHead->prev = p;
  289. p->next = pHead;
  290. }
  291. p->prev = nullptr;
  292. pHead = p;
  293. }
  294. void ParticleSystem::insertRandom(particle *p)
  295. {
  296. // Nonuniform, but 64-bit is so large nobody will notice. Hopefully.
  297. uint64 pos = rng.rand() % ((int64) activeParticles + 1);
  298. // Special case where the particle gets inserted before the head.
  299. if (pos == activeParticles)
  300. {
  301. particle *pA = pHead;
  302. if (pA)
  303. pA->prev = p;
  304. p->prev = nullptr;
  305. p->next = pA;
  306. pHead = p;
  307. return;
  308. }
  309. // Inserts the particle after the randomly selected particle.
  310. particle *pA = pMem + pos;
  311. particle *pB = pA->next;
  312. pA->next = p;
  313. if (pB)
  314. pB->prev = p;
  315. else
  316. pTail = p;
  317. p->prev = pA;
  318. p->next = pB;
  319. }
  320. ParticleSystem::particle *ParticleSystem::removeParticle(particle *p)
  321. {
  322. // The linked list is updated in this function and old pointers may be
  323. // invalidated. The returned pointer will inform the caller of the new
  324. // pointer to the next particle.
  325. particle *pNext = nullptr;
  326. // Removes the particle from the linked list.
  327. if (p->prev)
  328. p->prev->next = p->next;
  329. else
  330. pHead = p->next;
  331. if (p->next)
  332. {
  333. p->next->prev = p->prev;
  334. pNext = p->next;
  335. }
  336. else
  337. pTail = p->prev;
  338. // The (in memory) last particle can now be moved into the free slot.
  339. // It will skip the moving if it happens to be the removed particle.
  340. pFree--;
  341. if (p != pFree)
  342. {
  343. *p = *pFree;
  344. if (pNext == pFree)
  345. pNext = p;
  346. if (p->prev)
  347. p->prev->next = p;
  348. else
  349. pHead = p;
  350. if (p->next)
  351. p->next->prev = p;
  352. else
  353. pTail = p;
  354. }
  355. activeParticles--;
  356. return pNext;
  357. }
  358. void ParticleSystem::setTexture(Texture *texture)
  359. {
  360. Object::AutoRelease imagerelease(this->texture);
  361. this->texture = texture;
  362. if (texture)
  363. texture->retain();
  364. }
  365. Texture *ParticleSystem::getTexture() const
  366. {
  367. return texture;
  368. }
  369. void ParticleSystem::setInsertMode(InsertMode mode)
  370. {
  371. insertMode = mode;
  372. }
  373. ParticleSystem::InsertMode ParticleSystem::getInsertMode() const
  374. {
  375. return insertMode;
  376. }
  377. void ParticleSystem::setEmissionRate(float rate)
  378. {
  379. if (rate < 0.0f)
  380. throw love::Exception("Invalid emission rate");
  381. emissionRate = rate;
  382. }
  383. float ParticleSystem::getEmissionRate() const
  384. {
  385. return emissionRate;
  386. }
  387. void ParticleSystem::setEmitterLifetime(float life)
  388. {
  389. this->life = lifetime = life;
  390. }
  391. float ParticleSystem::getEmitterLifetime() const
  392. {
  393. return lifetime;
  394. }
  395. void ParticleSystem::setParticleLifetime(float min, float max)
  396. {
  397. particleLifeMin = min;
  398. if (max == 0)
  399. particleLifeMax = min;
  400. else
  401. particleLifeMax = max;
  402. }
  403. void ParticleSystem::getParticleLifetime(float *min, float *max) const
  404. {
  405. if (min)
  406. *min = particleLifeMin;
  407. if (max)
  408. *max = particleLifeMax;
  409. }
  410. void ParticleSystem::setPosition(float x, float y)
  411. {
  412. position = love::Vector(x, y);
  413. }
  414. const love::Vector &ParticleSystem::getPosition() const
  415. {
  416. return position;
  417. }
  418. void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
  419. {
  420. areaSpread = love::Vector(x, y);
  421. areaSpreadDistribution = distribution;
  422. }
  423. ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
  424. {
  425. return areaSpreadDistribution;
  426. }
  427. const love::Vector &ParticleSystem::getAreaSpreadParameters() const
  428. {
  429. return areaSpread;
  430. }
  431. void ParticleSystem::setDirection(float direction)
  432. {
  433. this->direction = direction;
  434. }
  435. float ParticleSystem::getDirection() const
  436. {
  437. return direction;
  438. }
  439. void ParticleSystem::setSpread(float spread)
  440. {
  441. this->spread = spread;
  442. }
  443. float ParticleSystem::getSpread() const
  444. {
  445. return spread;
  446. }
  447. void ParticleSystem::setSpeed(float speed)
  448. {
  449. speedMin = speedMax = speed;
  450. }
  451. void ParticleSystem::setSpeed(float min, float max)
  452. {
  453. speedMin = min;
  454. speedMax = max;
  455. }
  456. void ParticleSystem::getSpeed(float *min, float *max) const
  457. {
  458. if (min)
  459. *min = speedMin;
  460. if (max)
  461. *max = speedMax;
  462. }
  463. void ParticleSystem::setLinearAcceleration(float x, float y)
  464. {
  465. linearAccelerationMin.x = linearAccelerationMax.x = x;
  466. linearAccelerationMin.y = linearAccelerationMax.y = y;
  467. }
  468. void ParticleSystem::setLinearAcceleration(float xmin, float ymin, float xmax, float ymax)
  469. {
  470. linearAccelerationMin = love::Vector(xmin, ymin);
  471. linearAccelerationMax = love::Vector(xmax, ymax);
  472. }
  473. void ParticleSystem::getLinearAcceleration(love::Vector *min, love::Vector *max) const
  474. {
  475. if (min)
  476. *min = linearAccelerationMin;
  477. if (max)
  478. *max = linearAccelerationMax;
  479. }
  480. void ParticleSystem::setRadialAcceleration(float acceleration)
  481. {
  482. radialAccelerationMin = radialAccelerationMax = acceleration;
  483. }
  484. void ParticleSystem::setRadialAcceleration(float min, float max)
  485. {
  486. radialAccelerationMin = min;
  487. radialAccelerationMax = max;
  488. }
  489. void ParticleSystem::getRadialAcceleration(float *min, float *max) const
  490. {
  491. if (min)
  492. *min = radialAccelerationMin;
  493. if (max)
  494. *max = radialAccelerationMax;
  495. }
  496. void ParticleSystem::setTangentialAcceleration(float acceleration)
  497. {
  498. tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
  499. }
  500. void ParticleSystem::setTangentialAcceleration(float min, float max)
  501. {
  502. tangentialAccelerationMin = min;
  503. tangentialAccelerationMax = max;
  504. }
  505. void ParticleSystem::getTangentialAcceleration(float *min, float *max) const
  506. {
  507. if (min)
  508. *min = tangentialAccelerationMin;
  509. if (max)
  510. *max = tangentialAccelerationMax;
  511. }
  512. void ParticleSystem::setSize(float size)
  513. {
  514. sizes.resize(1);
  515. sizes[0] = size;
  516. }
  517. void ParticleSystem::setSizes(const std::vector<float> &newSizes)
  518. {
  519. sizes = newSizes;
  520. }
  521. const std::vector<float> &ParticleSystem::getSizes() const
  522. {
  523. return sizes;
  524. }
  525. void ParticleSystem::setSizeVariation(float variation)
  526. {
  527. sizeVariation = variation;
  528. }
  529. float ParticleSystem::getSizeVariation() const
  530. {
  531. return sizeVariation;
  532. }
  533. void ParticleSystem::setRotation(float rotation)
  534. {
  535. rotationMin = rotationMax = rotation;
  536. }
  537. void ParticleSystem::setRotation(float min, float max)
  538. {
  539. rotationMin = min;
  540. rotationMax = max;
  541. }
  542. void ParticleSystem::getRotation(float *min, float *max) const
  543. {
  544. if (min)
  545. *min = rotationMin;
  546. if (max)
  547. *max = rotationMax;
  548. }
  549. void ParticleSystem::setSpin(float spin)
  550. {
  551. spinStart = spin;
  552. spinEnd = spin;
  553. }
  554. void ParticleSystem::setSpin(float start, float end)
  555. {
  556. spinStart = start;
  557. spinEnd = end;
  558. }
  559. void ParticleSystem::getSpin(float *start, float *end) const
  560. {
  561. if (start)
  562. *start = spinStart;
  563. if (end)
  564. *end = spinEnd;
  565. }
  566. void ParticleSystem::setSpinVariation(float variation)
  567. {
  568. spinVariation = variation;
  569. }
  570. float ParticleSystem::getSpinVariation() const
  571. {
  572. return spinVariation;
  573. }
  574. void ParticleSystem::setOffset(float x, float y)
  575. {
  576. offsetX = x;
  577. offsetY = y;
  578. }
  579. love::Vector ParticleSystem::getOffset() const
  580. {
  581. return love::Vector(offsetX, offsetY);
  582. }
  583. void ParticleSystem::setColor(const Color &color)
  584. {
  585. colors.resize(1);
  586. colors[0] = colorToFloat(color);
  587. }
  588. void ParticleSystem::setColor(const std::vector<Color> &newColors)
  589. {
  590. colors.resize(newColors.size());
  591. for (size_t i = 0; i < newColors.size(); ++i)
  592. colors[i] = colorToFloat(newColors[i]);
  593. }
  594. std::vector<Color> ParticleSystem::getColor() const
  595. {
  596. // The particle system stores colors as floats...
  597. std::vector<Color> ncolors(colors.size());
  598. for (size_t i = 0; i < colors.size(); ++i)
  599. {
  600. ncolors[i].r = (unsigned char) (colors[i].r * 255);
  601. ncolors[i].g = (unsigned char) (colors[i].g * 255);
  602. ncolors[i].b = (unsigned char) (colors[i].b * 255);
  603. ncolors[i].a = (unsigned char) (colors[i].a * 255);
  604. }
  605. return ncolors;
  606. }
  607. uint32 ParticleSystem::getCount() const
  608. {
  609. return activeParticles;
  610. }
  611. void ParticleSystem::start()
  612. {
  613. active = true;
  614. }
  615. void ParticleSystem::stop()
  616. {
  617. active = false;
  618. life = lifetime;
  619. emitCounter = 0;
  620. }
  621. void ParticleSystem::pause()
  622. {
  623. active = false;
  624. }
  625. void ParticleSystem::reset()
  626. {
  627. if (pMem == nullptr)
  628. return;
  629. pFree = pMem;
  630. pHead = nullptr;
  631. pTail = nullptr;
  632. activeParticles = 0;
  633. life = lifetime;
  634. emitCounter = 0;
  635. }
  636. void ParticleSystem::emit(uint32 num)
  637. {
  638. if (!active)
  639. return;
  640. num = std::min(num, maxParticles - activeParticles);
  641. while(num--)
  642. addParticle(1.0f);
  643. }
  644. bool ParticleSystem::isActive() const
  645. {
  646. return active;
  647. }
  648. bool ParticleSystem::isPaused() const
  649. {
  650. return !active && life < lifetime;
  651. }
  652. bool ParticleSystem::isStopped() const
  653. {
  654. return !active && life >= lifetime;
  655. }
  656. bool ParticleSystem::isEmpty() const
  657. {
  658. return activeParticles == 0;
  659. }
  660. bool ParticleSystem::isFull() const
  661. {
  662. return activeParticles == maxParticles;
  663. }
  664. void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  665. {
  666. uint32 pCount = getCount();
  667. if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr)
  668. return;
  669. Color curcolor = gl.getColor();
  670. glPushMatrix();
  671. static Matrix t;
  672. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  673. glMultMatrixf((const GLfloat *)t.getElements());
  674. const Vertex *textureVerts = texture->getVertices();
  675. Vertex *pVerts = particleVerts;
  676. particle *p = pHead;
  677. // set the vertex data for each particle (transformation, texcoords, color)
  678. while (p)
  679. {
  680. // particle vertices are image vertices transformed by particle information
  681. t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
  682. t.transform(pVerts, textureVerts, 4);
  683. // set the texture coordinate and color data for particle vertices
  684. for (int v = 0; v < 4; v++)
  685. {
  686. pVerts[v].s = textureVerts[v].s;
  687. pVerts[v].t = textureVerts[v].t;
  688. // particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255)
  689. pVerts[v].r = (unsigned char) (p->color.r*255);
  690. pVerts[v].g = (unsigned char) (p->color.g*255);
  691. pVerts[v].b = (unsigned char) (p->color.b*255);
  692. pVerts[v].a = (unsigned char) (p->color.a*255);
  693. }
  694. pVerts += 4;
  695. p = p->next;
  696. }
  697. texture->predraw();
  698. glEnableClientState(GL_COLOR_ARRAY);
  699. glEnableClientState(GL_VERTEX_ARRAY);
  700. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  701. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid *) &particleVerts[0].r);
  702. glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].x);
  703. glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].s);
  704. gl.prepareDraw();
  705. glDrawArrays(GL_QUADS, 0, pCount * 4);
  706. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  707. glDisableClientState(GL_VERTEX_ARRAY);
  708. glDisableClientState(GL_COLOR_ARRAY);
  709. texture->postdraw();
  710. glPopMatrix();
  711. gl.setColor(curcolor);
  712. }
  713. void ParticleSystem::update(float dt)
  714. {
  715. if (pMem == nullptr || dt == 0.0f)
  716. return;
  717. // Traverse all particles and update.
  718. particle *p = pHead;
  719. while (p)
  720. {
  721. // Decrease lifespan.
  722. p->life -= dt;
  723. if (p->life <= 0)
  724. p = removeParticle(p);
  725. else
  726. {
  727. // Temp variables.
  728. love::Vector radial, tangential;
  729. love::Vector ppos(p->position[0], p->position[1]);
  730. // Get vector from particle center to particle.
  731. radial = ppos - p->origin;
  732. radial.normalize();
  733. tangential = radial;
  734. // Resize radial acceleration.
  735. radial *= p->radialAcceleration;
  736. // Calculate tangential acceleration.
  737. {
  738. float a = tangential.getX();
  739. tangential.setX(-tangential.getY());
  740. tangential.setY(a);
  741. }
  742. // Resize tangential.
  743. tangential *= p->tangentialAcceleration;
  744. // Update position.
  745. p->speed += (radial+tangential+p->linearAcceleration)*dt;
  746. // Modify position.
  747. ppos += p->speed * dt;
  748. p->position[0] = ppos.getX();
  749. p->position[1] = ppos.getY();
  750. const float t = 1.0f - p->life / p->lifetime;
  751. // Rotate.
  752. p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt;
  753. // Change size according to given intervals:
  754. // i = 0 1 2 3 n-1
  755. // |-------|-------|------|--- ... ---|
  756. // t = 0 1/(n-1) 3/(n-1) 1
  757. //
  758. // `s' is the interpolation variable scaled to the current
  759. // interval width, e.g. if n = 5 and t = 0.3, then the current
  760. // indices are 1,2 and s = 0.3 - 0.25 = 0.05
  761. float s = p->sizeOffset + t * p->sizeIntervalSize; // size variation
  762. s *= (float)(sizes.size() - 1); // 0 <= s < sizes.size()
  763. size_t i = (size_t)s;
  764. size_t k = (i == sizes.size() - 1) ? i : i + 1; // boundary check (prevents failing on t = 1.0f)
  765. s -= (float)i; // transpose s to be in interval [0:1]: i <= s < i + 1 ~> 0 <= s < 1
  766. p->size = sizes[i] * (1.0f - s) + sizes[k] * s;
  767. // Update color according to given intervals (as above)
  768. s = t * (float)(colors.size() - 1);
  769. i = (size_t)s;
  770. k = (i == colors.size() - 1) ? i : i + 1;
  771. s -= (float)i; // 0 <= s <= 1
  772. p->color = colors[i] * (1.0f - s) + colors[k] * s;
  773. // Next particle.
  774. p = p->next;
  775. }
  776. }
  777. // Make some more particles.
  778. if (active)
  779. {
  780. float rate = 1.0f / emissionRate; // the amount of time between each particle emit
  781. emitCounter += dt;
  782. float total = emitCounter - rate;
  783. while (emitCounter > rate)
  784. {
  785. addParticle(1.0f - (emitCounter - rate) / total);
  786. emitCounter -= rate;
  787. }
  788. /*int particles = (int)(emissionRate * dt);
  789. for (int i = 0; i != particles; i++)
  790. add();*/
  791. life -= dt;
  792. if (lifetime != -1 && life < 0)
  793. stop();
  794. }
  795. prevPosition = position;
  796. }
  797. bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
  798. {
  799. return distributions.find(in, out);
  800. }
  801. bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
  802. {
  803. return distributions.find(in, out);
  804. }
  805. bool ParticleSystem::getConstant(const char *in, InsertMode &out)
  806. {
  807. return insertModes.find(in, out);
  808. }
  809. bool ParticleSystem::getConstant(InsertMode in, const char *&out)
  810. {
  811. return insertModes.find(in, out);
  812. }
  813. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] =
  814. {
  815. { "none", ParticleSystem::DISTRIBUTION_NONE },
  816. { "uniform", ParticleSystem::DISTRIBUTION_UNIFORM },
  817. { "normal", ParticleSystem::DISTRIBUTION_NORMAL },
  818. };
  819. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
  820. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM>::Entry ParticleSystem::insertModesEntries[] =
  821. {
  822. { "top", ParticleSystem::INSERT_MODE_TOP },
  823. { "bottom", ParticleSystem::INSERT_MODE_BOTTOM },
  824. { "random", ParticleSystem::INSERT_MODE_RANDOM },
  825. };
  826. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM> ParticleSystem::insertModes(ParticleSystem::insertModesEntries, sizeof(ParticleSystem::insertModesEntries));
  827. } // opengl
  828. } // graphics
  829. } // love