ParticleSystem.cpp 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. /**
  2. * Copyright (c) 2006-2015 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. float calculate_variation(float inner, float outer, float var)
  40. {
  41. float low = inner - (outer/2.0f)*var;
  42. float high = inner + (outer/2.0f)*var;
  43. float r = (float) rng.random();
  44. return low*(1-r)+high*r;
  45. }
  46. } // anonymous namespace
  47. ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
  48. : pMem(nullptr)
  49. , pFree(nullptr)
  50. , pHead(nullptr)
  51. , pTail(nullptr)
  52. , particleVerts(nullptr)
  53. , quadIndices(1)
  54. , texture(texture)
  55. , active(true)
  56. , insertMode(INSERT_MODE_TOP)
  57. , maxParticles(0)
  58. , activeParticles(0)
  59. , emissionRate(0)
  60. , emitCounter(0)
  61. , areaSpreadDistribution(DISTRIBUTION_NONE)
  62. , lifetime(-1)
  63. , life(0)
  64. , particleLifeMin(0)
  65. , particleLifeMax(0)
  66. , direction(0)
  67. , spread(0)
  68. , speedMin(0)
  69. , speedMax(0)
  70. , linearAccelerationMin(0, 0)
  71. , linearAccelerationMax(0, 0)
  72. , radialAccelerationMin(0)
  73. , radialAccelerationMax(0)
  74. , tangentialAccelerationMin(0)
  75. , tangentialAccelerationMax(0)
  76. , linearDampingMin(0.0f)
  77. , linearDampingMax(0.0f)
  78. , sizeVariation(0)
  79. , rotationMin(0)
  80. , rotationMax(0)
  81. , spinStart(0)
  82. , spinEnd(0)
  83. , spinVariation(0)
  84. , offset(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f)
  85. , defaultOffset(true)
  86. , relativeRotation(false)
  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. }
  94. ParticleSystem::ParticleSystem(const ParticleSystem &p)
  95. : pMem(nullptr)
  96. , pFree(nullptr)
  97. , pHead(nullptr)
  98. , pTail(nullptr)
  99. , particleVerts(nullptr)
  100. , quadIndices(p.quadIndices)
  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. , linearDampingMin(p.linearDampingMin)
  127. , linearDampingMax(p.linearDampingMax)
  128. , sizes(p.sizes)
  129. , sizeVariation(p.sizeVariation)
  130. , rotationMin(p.rotationMin)
  131. , rotationMax(p.rotationMax)
  132. , spinStart(p.spinStart)
  133. , spinEnd(p.spinEnd)
  134. , spinVariation(p.spinVariation)
  135. , offset(p.offset)
  136. , defaultOffset(p.defaultOffset)
  137. , colors(p.colors)
  138. , quads(p.quads)
  139. , relativeRotation(p.relativeRotation)
  140. {
  141. setBufferSize(maxParticles);
  142. }
  143. ParticleSystem::~ParticleSystem()
  144. {
  145. deleteBuffers();
  146. }
  147. ParticleSystem *ParticleSystem::clone()
  148. {
  149. return new ParticleSystem(*this);
  150. }
  151. void ParticleSystem::resetOffset()
  152. {
  153. if (quads.empty())
  154. offset = love::Vector(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f);
  155. else
  156. {
  157. Quad::Viewport v = quads[0]->getViewport();
  158. offset = love::Vector(v.x*0.5f, v.y*0.5f);
  159. }
  160. }
  161. void ParticleSystem::createBuffers(size_t size)
  162. {
  163. try
  164. {
  165. pFree = pMem = new Particle[size];
  166. particleVerts = new love::Vertex[size * 4];
  167. maxParticles = (uint32) size;
  168. }
  169. catch (std::bad_alloc &)
  170. {
  171. deleteBuffers();
  172. throw love::Exception("Out of memory");
  173. }
  174. }
  175. void ParticleSystem::deleteBuffers()
  176. {
  177. // Clean up for great gracefulness!
  178. delete[] pMem;
  179. delete[] particleVerts;
  180. pMem = nullptr;
  181. particleVerts = nullptr;
  182. maxParticles = 0;
  183. activeParticles = 0;
  184. }
  185. void ParticleSystem::setBufferSize(uint32 size)
  186. {
  187. if (size == 0 || size > MAX_PARTICLES)
  188. throw love::Exception("Invalid buffer size");
  189. quadIndices = QuadIndices(size);
  190. deleteBuffers();
  191. createBuffers(size);
  192. reset();
  193. }
  194. uint32 ParticleSystem::getBufferSize() const
  195. {
  196. return maxParticles;
  197. }
  198. void ParticleSystem::addParticle(float t)
  199. {
  200. if (isFull())
  201. return;
  202. // Gets a free particle and updates the allocation pointer.
  203. Particle *p = pFree++;
  204. initParticle(p, t);
  205. switch (insertMode)
  206. {
  207. default:
  208. case INSERT_MODE_TOP:
  209. insertTop(p);
  210. break;
  211. case INSERT_MODE_BOTTOM:
  212. insertBottom(p);
  213. break;
  214. case INSERT_MODE_RANDOM:
  215. insertRandom(p);
  216. break;
  217. }
  218. activeParticles++;
  219. }
  220. void ParticleSystem::initParticle(Particle *p, float t)
  221. {
  222. float min,max;
  223. // Linearly interpolate between the previous and current emitter position.
  224. love::Vector pos = prevPosition + (position - prevPosition) * t;
  225. min = particleLifeMin;
  226. max = particleLifeMax;
  227. if (min == max)
  228. p->life = min;
  229. else
  230. p->life = (float) rng.random(min, max);
  231. p->lifetime = p->life;
  232. p->position = pos;
  233. switch (areaSpreadDistribution)
  234. {
  235. case DISTRIBUTION_UNIFORM:
  236. p->position.x += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
  237. p->position.y += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
  238. break;
  239. case DISTRIBUTION_NORMAL:
  240. p->position.x += (float) rng.randomNormal(areaSpread.getX());
  241. p->position.y += (float) rng.randomNormal(areaSpread.getY());
  242. break;
  243. case DISTRIBUTION_NONE:
  244. default:
  245. break;
  246. }
  247. p->origin = pos;
  248. min = speedMin;
  249. max = speedMax;
  250. float speed = (float) rng.random(min, max);
  251. min = direction - spread/2.0f;
  252. max = direction + spread/2.0f;
  253. float dir = (float) rng.random(min, max);
  254. p->velocity = love::Vector(cosf(dir), sinf(dir)) * speed;
  255. p->linearAcceleration.x = (float) rng.random(linearAccelerationMin.x, linearAccelerationMax.x);
  256. p->linearAcceleration.y = (float) rng.random(linearAccelerationMin.y, linearAccelerationMax.y);
  257. min = radialAccelerationMin;
  258. max = radialAccelerationMax;
  259. p->radialAcceleration = (float) rng.random(min, max);
  260. min = tangentialAccelerationMin;
  261. max = tangentialAccelerationMax;
  262. p->tangentialAcceleration = (float) rng.random(min, max);
  263. min = linearDampingMin;
  264. max = linearDampingMax;
  265. p->linearDamping = (float) rng.random(min, max);
  266. p->sizeOffset = (float) rng.random(sizeVariation); // time offset for size change
  267. p->sizeIntervalSize = (1.0f - (float) rng.random(sizeVariation)) - p->sizeOffset;
  268. p->size = sizes[(size_t)(p->sizeOffset - .5f) * (sizes.size() - 1)];
  269. min = rotationMin;
  270. max = rotationMax;
  271. p->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
  272. p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
  273. p->rotation = (float) rng.random(min, max);
  274. p->angle = p->rotation;
  275. if (relativeRotation)
  276. p->angle += atan2f(p->velocity.y, p->velocity.x);
  277. p->color = colors[0];
  278. p->quadIndex = 0;
  279. }
  280. void ParticleSystem::insertTop(Particle *p)
  281. {
  282. if (pHead == nullptr)
  283. {
  284. pHead = p;
  285. p->prev = nullptr;
  286. }
  287. else
  288. {
  289. pTail->next = p;
  290. p->prev = pTail;
  291. }
  292. p->next = nullptr;
  293. pTail = p;
  294. }
  295. void ParticleSystem::insertBottom(Particle *p)
  296. {
  297. if (pTail == nullptr)
  298. {
  299. pTail = p;
  300. p->next = nullptr;
  301. }
  302. else
  303. {
  304. pHead->prev = p;
  305. p->next = pHead;
  306. }
  307. p->prev = nullptr;
  308. pHead = p;
  309. }
  310. void ParticleSystem::insertRandom(Particle *p)
  311. {
  312. // Nonuniform, but 64-bit is so large nobody will notice. Hopefully.
  313. uint64 pos = rng.rand() % ((int64) activeParticles + 1);
  314. // Special case where the particle gets inserted before the head.
  315. if (pos == activeParticles)
  316. {
  317. Particle *pA = pHead;
  318. if (pA)
  319. pA->prev = p;
  320. p->prev = nullptr;
  321. p->next = pA;
  322. pHead = p;
  323. return;
  324. }
  325. // Inserts the particle after the randomly selected particle.
  326. Particle *pA = pMem + pos;
  327. Particle *pB = pA->next;
  328. pA->next = p;
  329. if (pB)
  330. pB->prev = p;
  331. else
  332. pTail = p;
  333. p->prev = pA;
  334. p->next = pB;
  335. }
  336. ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p)
  337. {
  338. // The linked list is updated in this function and old pointers may be
  339. // invalidated. The returned pointer will inform the caller of the new
  340. // pointer to the next particle.
  341. Particle *pNext = nullptr;
  342. // Removes the particle from the linked list.
  343. if (p->prev)
  344. p->prev->next = p->next;
  345. else
  346. pHead = p->next;
  347. if (p->next)
  348. {
  349. p->next->prev = p->prev;
  350. pNext = p->next;
  351. }
  352. else
  353. pTail = p->prev;
  354. // The (in memory) last particle can now be moved into the free slot.
  355. // It will skip the moving if it happens to be the removed particle.
  356. pFree--;
  357. if (p != pFree)
  358. {
  359. *p = *pFree;
  360. if (pNext == pFree)
  361. pNext = p;
  362. if (p->prev)
  363. p->prev->next = p;
  364. else
  365. pHead = p;
  366. if (p->next)
  367. p->next->prev = p;
  368. else
  369. pTail = p;
  370. }
  371. activeParticles--;
  372. return pNext;
  373. }
  374. void ParticleSystem::setTexture(Texture *tex)
  375. {
  376. texture.set(tex);
  377. if (defaultOffset)
  378. resetOffset();
  379. }
  380. Texture *ParticleSystem::getTexture() const
  381. {
  382. return texture.get();
  383. }
  384. void ParticleSystem::setInsertMode(InsertMode mode)
  385. {
  386. insertMode = mode;
  387. }
  388. ParticleSystem::InsertMode ParticleSystem::getInsertMode() const
  389. {
  390. return insertMode;
  391. }
  392. void ParticleSystem::setEmissionRate(float rate)
  393. {
  394. if (rate < 0.0f)
  395. throw love::Exception("Invalid emission rate");
  396. emissionRate = rate;
  397. }
  398. float ParticleSystem::getEmissionRate() const
  399. {
  400. return emissionRate;
  401. }
  402. void ParticleSystem::setEmitterLifetime(float life)
  403. {
  404. this->life = lifetime = life;
  405. }
  406. float ParticleSystem::getEmitterLifetime() const
  407. {
  408. return lifetime;
  409. }
  410. void ParticleSystem::setParticleLifetime(float min, float max)
  411. {
  412. particleLifeMin = min;
  413. if (max == 0)
  414. particleLifeMax = min;
  415. else
  416. particleLifeMax = max;
  417. }
  418. void ParticleSystem::getParticleLifetime(float &min, float &max) const
  419. {
  420. min = particleLifeMin;
  421. max = particleLifeMax;
  422. }
  423. void ParticleSystem::setPosition(float x, float y)
  424. {
  425. position = love::Vector(x, y);
  426. prevPosition = position;
  427. }
  428. const love::Vector &ParticleSystem::getPosition() const
  429. {
  430. return position;
  431. }
  432. void ParticleSystem::moveTo(float x, float y)
  433. {
  434. position = love::Vector(x, y);
  435. }
  436. void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
  437. {
  438. areaSpread = love::Vector(x, y);
  439. areaSpreadDistribution = distribution;
  440. }
  441. ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
  442. {
  443. return areaSpreadDistribution;
  444. }
  445. const love::Vector &ParticleSystem::getAreaSpreadParameters() const
  446. {
  447. return areaSpread;
  448. }
  449. void ParticleSystem::setDirection(float direction)
  450. {
  451. this->direction = direction;
  452. }
  453. float ParticleSystem::getDirection() const
  454. {
  455. return direction;
  456. }
  457. void ParticleSystem::setSpread(float spread)
  458. {
  459. this->spread = spread;
  460. }
  461. float ParticleSystem::getSpread() const
  462. {
  463. return spread;
  464. }
  465. void ParticleSystem::setSpeed(float speed)
  466. {
  467. speedMin = speedMax = speed;
  468. }
  469. void ParticleSystem::setSpeed(float min, float max)
  470. {
  471. speedMin = min;
  472. speedMax = max;
  473. }
  474. void ParticleSystem::getSpeed(float &min, float &max) const
  475. {
  476. min = speedMin;
  477. max = speedMax;
  478. }
  479. void ParticleSystem::setLinearAcceleration(float x, float y)
  480. {
  481. linearAccelerationMin.x = linearAccelerationMax.x = x;
  482. linearAccelerationMin.y = linearAccelerationMax.y = y;
  483. }
  484. void ParticleSystem::setLinearAcceleration(float xmin, float ymin, float xmax, float ymax)
  485. {
  486. linearAccelerationMin = love::Vector(xmin, ymin);
  487. linearAccelerationMax = love::Vector(xmax, ymax);
  488. }
  489. void ParticleSystem::getLinearAcceleration(love::Vector &min, love::Vector &max) const
  490. {
  491. min = linearAccelerationMin;
  492. max = linearAccelerationMax;
  493. }
  494. void ParticleSystem::setRadialAcceleration(float acceleration)
  495. {
  496. radialAccelerationMin = radialAccelerationMax = acceleration;
  497. }
  498. void ParticleSystem::setRadialAcceleration(float min, float max)
  499. {
  500. radialAccelerationMin = min;
  501. radialAccelerationMax = max;
  502. }
  503. void ParticleSystem::getRadialAcceleration(float &min, float &max) const
  504. {
  505. min = radialAccelerationMin;
  506. max = radialAccelerationMax;
  507. }
  508. void ParticleSystem::setTangentialAcceleration(float acceleration)
  509. {
  510. tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
  511. }
  512. void ParticleSystem::setTangentialAcceleration(float min, float max)
  513. {
  514. tangentialAccelerationMin = min;
  515. tangentialAccelerationMax = max;
  516. }
  517. void ParticleSystem::getTangentialAcceleration(float &min, float &max) const
  518. {
  519. min = tangentialAccelerationMin;
  520. max = tangentialAccelerationMax;
  521. }
  522. void ParticleSystem::setLinearDamping(float min, float max)
  523. {
  524. linearDampingMin = min;
  525. linearDampingMax = max;
  526. }
  527. void ParticleSystem::getLinearDamping(float &min, float &max) const
  528. {
  529. min = linearDampingMin;
  530. max = linearDampingMax;
  531. }
  532. void ParticleSystem::setSize(float size)
  533. {
  534. sizes.resize(1);
  535. sizes[0] = size;
  536. }
  537. void ParticleSystem::setSizes(const std::vector<float> &newSizes)
  538. {
  539. sizes = newSizes;
  540. }
  541. const std::vector<float> &ParticleSystem::getSizes() const
  542. {
  543. return sizes;
  544. }
  545. void ParticleSystem::setSizeVariation(float variation)
  546. {
  547. sizeVariation = variation;
  548. }
  549. float ParticleSystem::getSizeVariation() const
  550. {
  551. return sizeVariation;
  552. }
  553. void ParticleSystem::setRotation(float rotation)
  554. {
  555. rotationMin = rotationMax = rotation;
  556. }
  557. void ParticleSystem::setRotation(float min, float max)
  558. {
  559. rotationMin = min;
  560. rotationMax = max;
  561. }
  562. void ParticleSystem::getRotation(float &min, float &max) const
  563. {
  564. min = rotationMin;
  565. max = rotationMax;
  566. }
  567. void ParticleSystem::setSpin(float spin)
  568. {
  569. spinStart = spin;
  570. spinEnd = spin;
  571. }
  572. void ParticleSystem::setSpin(float start, float end)
  573. {
  574. spinStart = start;
  575. spinEnd = end;
  576. }
  577. void ParticleSystem::getSpin(float &start, float &end) const
  578. {
  579. start = spinStart;
  580. end = spinEnd;
  581. }
  582. void ParticleSystem::setSpinVariation(float variation)
  583. {
  584. spinVariation = variation;
  585. }
  586. float ParticleSystem::getSpinVariation() const
  587. {
  588. return spinVariation;
  589. }
  590. void ParticleSystem::setOffset(float x, float y)
  591. {
  592. offset = love::Vector(x, y);
  593. defaultOffset = false;
  594. }
  595. love::Vector ParticleSystem::getOffset() const
  596. {
  597. return offset;
  598. }
  599. void ParticleSystem::setColor(const std::vector<Colorf> &newColors)
  600. {
  601. colors = newColors;
  602. for (Colorf &c : colors)
  603. {
  604. // We want to store the colors as [0, 1], rather than [0, 255].
  605. c.r /= 255.0f;
  606. c.g /= 255.0f;
  607. c.b /= 255.0f;
  608. c.a /= 255.0f;
  609. }
  610. }
  611. std::vector<Colorf> ParticleSystem::getColor() const
  612. {
  613. // The particle system stores colors in the range of [0, 1]...
  614. std::vector<Colorf> ncolors(colors);
  615. for (Colorf &c : ncolors)
  616. {
  617. c.r *= 255.0f;
  618. c.g *= 255.0f;
  619. c.b *= 255.0f;
  620. c.a *= 255.0f;
  621. }
  622. return ncolors;
  623. }
  624. void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
  625. {
  626. std::vector<StrongRef<Quad>> quadlist;
  627. quadlist.reserve(newQuads.size());
  628. for (Quad *q : newQuads)
  629. quadlist.push_back(q);
  630. quads = quadlist;
  631. if (defaultOffset)
  632. resetOffset();
  633. }
  634. void ParticleSystem::setQuads()
  635. {
  636. quads.clear();
  637. }
  638. std::vector<Quad *> ParticleSystem::getQuads() const
  639. {
  640. std::vector<Quad *> quadlist;
  641. quadlist.reserve(quads.size());
  642. for (const StrongRef<Quad> &q : quads)
  643. quadlist.push_back(q.get());
  644. return quadlist;
  645. }
  646. void ParticleSystem::setRelativeRotation(bool enable)
  647. {
  648. relativeRotation = enable;
  649. }
  650. bool ParticleSystem::hasRelativeRotation() const
  651. {
  652. return relativeRotation;
  653. }
  654. uint32 ParticleSystem::getCount() const
  655. {
  656. return activeParticles;
  657. }
  658. void ParticleSystem::start()
  659. {
  660. active = true;
  661. }
  662. void ParticleSystem::stop()
  663. {
  664. active = false;
  665. life = lifetime;
  666. emitCounter = 0;
  667. }
  668. void ParticleSystem::pause()
  669. {
  670. active = false;
  671. }
  672. void ParticleSystem::reset()
  673. {
  674. if (pMem == nullptr)
  675. return;
  676. pFree = pMem;
  677. pHead = nullptr;
  678. pTail = nullptr;
  679. activeParticles = 0;
  680. life = lifetime;
  681. emitCounter = 0;
  682. }
  683. void ParticleSystem::emit(uint32 num)
  684. {
  685. if (!active)
  686. return;
  687. num = std::min(num, maxParticles - activeParticles);
  688. while(num--)
  689. addParticle(1.0f);
  690. }
  691. bool ParticleSystem::isActive() const
  692. {
  693. return active;
  694. }
  695. bool ParticleSystem::isPaused() const
  696. {
  697. return !active && life < lifetime;
  698. }
  699. bool ParticleSystem::isStopped() const
  700. {
  701. return !active && life >= lifetime;
  702. }
  703. bool ParticleSystem::isEmpty() const
  704. {
  705. return activeParticles == 0;
  706. }
  707. bool ParticleSystem::isFull() const
  708. {
  709. return activeParticles == maxParticles;
  710. }
  711. void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  712. {
  713. uint32 pCount = getCount();
  714. if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || particleVerts == nullptr)
  715. return;
  716. OpenGL::TempDebugGroup debuggroup("ParticleSystem draw");
  717. Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky);
  718. OpenGL::TempTransform transform(gl);
  719. transform.get() *= t;
  720. const Vertex *textureVerts = texture->getVertices();
  721. Vertex *pVerts = particleVerts;
  722. Particle *p = pHead;
  723. bool useQuads = !quads.empty();
  724. // set the vertex data for each particle (transformation, texcoords, color)
  725. while (p)
  726. {
  727. if (useQuads)
  728. textureVerts = quads[p->quadIndex]->getVertices();
  729. // particle vertices are image vertices transformed by particle info
  730. t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f);
  731. t.transform(pVerts, textureVerts, 4);
  732. // set the texture coordinate and color data for particle vertices
  733. for (int v = 0; v < 4; v++)
  734. {
  735. pVerts[v].s = textureVerts[v].s;
  736. pVerts[v].t = textureVerts[v].t;
  737. // Particle colors are stored as floats (0-1) but vertex colors are
  738. // unsigned bytes (0-255).
  739. pVerts[v].r = (unsigned char) (p->color.r*255);
  740. pVerts[v].g = (unsigned char) (p->color.g*255);
  741. pVerts[v].b = (unsigned char) (p->color.b*255);
  742. pVerts[v].a = (unsigned char) (p->color.a*255);
  743. }
  744. pVerts += 4;
  745. p = p->next;
  746. }
  747. gl.bindTexture(*(GLuint *) texture->getHandle());
  748. gl.prepareDraw();
  749. gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
  750. glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &particleVerts[0].r);
  751. glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x);
  752. glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s);
  753. {
  754. GLsizei count = (GLsizei) quadIndices.getIndexCount(pCount);
  755. GLBuffer::Bind ibo_bind(*quadIndices.getBuffer());
  756. gl.drawElements(GL_TRIANGLES, count, quadIndices.getType(), quadIndices.getPointer(0));
  757. }
  758. }
  759. void ParticleSystem::update(float dt)
  760. {
  761. if (pMem == nullptr || dt == 0.0f)
  762. return;
  763. // Traverse all particles and update.
  764. Particle *p = pHead;
  765. while (p)
  766. {
  767. // Decrease lifespan.
  768. p->life -= dt;
  769. if (p->life <= 0)
  770. p = removeParticle(p);
  771. else
  772. {
  773. // Temp variables.
  774. love::Vector radial, tangential;
  775. love::Vector ppos = p->position;
  776. // Get vector from particle center to particle.
  777. radial = ppos - p->origin;
  778. radial.normalize();
  779. tangential = radial;
  780. // Resize radial acceleration.
  781. radial *= p->radialAcceleration;
  782. // Calculate tangential acceleration.
  783. {
  784. float a = tangential.getX();
  785. tangential.setX(-tangential.getY());
  786. tangential.setY(a);
  787. }
  788. // Resize tangential.
  789. tangential *= p->tangentialAcceleration;
  790. // Update velocity.
  791. p->velocity += (radial + tangential + p->linearAcceleration) * dt;
  792. // Apply damping.
  793. p->velocity *= 1.0f / (1.0f + p->linearDamping * dt);
  794. // Modify position.
  795. ppos += p->velocity * dt;
  796. p->position = ppos;
  797. const float t = 1.0f - p->life / p->lifetime;
  798. // Rotate.
  799. p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt;
  800. p->angle = p->rotation;
  801. if (relativeRotation)
  802. p->angle += atan2f(p->velocity.y, p->velocity.x);
  803. // Change size according to given intervals:
  804. // i = 0 1 2 3 n-1
  805. // |-------|-------|------|--- ... ---|
  806. // t = 0 1/(n-1) 3/(n-1) 1
  807. //
  808. // `s' is the interpolation variable scaled to the current
  809. // interval width, e.g. if n = 5 and t = 0.3, then the current
  810. // indices are 1,2 and s = 0.3 - 0.25 = 0.05
  811. float s = p->sizeOffset + t * p->sizeIntervalSize; // size variation
  812. s *= (float)(sizes.size() - 1); // 0 <= s < sizes.size()
  813. size_t i = (size_t)s;
  814. size_t k = (i == sizes.size() - 1) ? i : i + 1; // boundary check (prevents failing on t = 1.0f)
  815. s -= (float)i; // transpose s to be in interval [0:1]: i <= s < i + 1 ~> 0 <= s < 1
  816. p->size = sizes[i] * (1.0f - s) + sizes[k] * s;
  817. // Update color according to given intervals (as above)
  818. s = t * (float)(colors.size() - 1);
  819. i = (size_t)s;
  820. k = (i == colors.size() - 1) ? i : i + 1;
  821. s -= (float)i; // 0 <= s <= 1
  822. p->color = colors[i] * (1.0f - s) + colors[k] * s;
  823. // Update the quad index.
  824. k = quads.size();
  825. if (k > 0)
  826. {
  827. s = t * (float) k; // [0:numquads-1] (clamped below)
  828. i = (s > 0.0f) ? (size_t) s : 0;
  829. p->quadIndex = (int) ((i < k) ? i : k - 1);
  830. }
  831. // Next particle.
  832. p = p->next;
  833. }
  834. }
  835. // Make some more particles.
  836. if (active)
  837. {
  838. float rate = 1.0f / emissionRate; // the amount of time between each particle emit
  839. emitCounter += dt;
  840. float total = emitCounter - rate;
  841. while (emitCounter > rate)
  842. {
  843. addParticle(1.0f - (emitCounter - rate) / total);
  844. emitCounter -= rate;
  845. }
  846. /*int particles = (int)(emissionRate * dt);
  847. for (int i = 0; i != particles; i++)
  848. add();*/
  849. life -= dt;
  850. if (lifetime != -1 && life < 0)
  851. stop();
  852. }
  853. prevPosition = position;
  854. }
  855. bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
  856. {
  857. return distributions.find(in, out);
  858. }
  859. bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
  860. {
  861. return distributions.find(in, out);
  862. }
  863. bool ParticleSystem::getConstant(const char *in, InsertMode &out)
  864. {
  865. return insertModes.find(in, out);
  866. }
  867. bool ParticleSystem::getConstant(InsertMode in, const char *&out)
  868. {
  869. return insertModes.find(in, out);
  870. }
  871. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] =
  872. {
  873. { "none", ParticleSystem::DISTRIBUTION_NONE },
  874. { "uniform", ParticleSystem::DISTRIBUTION_UNIFORM },
  875. { "normal", ParticleSystem::DISTRIBUTION_NORMAL },
  876. };
  877. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
  878. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM>::Entry ParticleSystem::insertModesEntries[] =
  879. {
  880. { "top", ParticleSystem::INSERT_MODE_TOP },
  881. { "bottom", ParticleSystem::INSERT_MODE_BOTTOM },
  882. { "random", ParticleSystem::INSERT_MODE_RANDOM },
  883. };
  884. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM> ParticleSystem::insertModes(ParticleSystem::insertModesEntries, sizeof(ParticleSystem::insertModesEntries));
  885. } // opengl
  886. } // graphics
  887. } // love