ParticleSystem.cpp 23 KB

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