ParticleSystem.cpp 23 KB

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