ParticleSystem.cpp 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  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. texture->retain();
  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. if (texture != nullptr)
  142. texture->retain();
  143. for (Quad *quad : quads)
  144. quad->retain();
  145. }
  146. ParticleSystem::~ParticleSystem()
  147. {
  148. if (texture != nullptr)
  149. texture->release();
  150. for (Quad *quad : quads)
  151. quad->release();
  152. deleteBuffers();
  153. }
  154. ParticleSystem *ParticleSystem::clone()
  155. {
  156. return new ParticleSystem(*this);
  157. }
  158. void ParticleSystem::createBuffers(size_t size)
  159. {
  160. try
  161. {
  162. pFree = pMem = new Particle[size];
  163. particleVerts = new love::Vertex[size * 4];
  164. maxParticles = (uint32) size;
  165. }
  166. catch (std::bad_alloc &)
  167. {
  168. deleteBuffers();
  169. throw love::Exception("Out of memory");
  170. }
  171. }
  172. void ParticleSystem::deleteBuffers()
  173. {
  174. // Clean up for great gracefulness!
  175. delete[] pMem;
  176. delete[] particleVerts;
  177. pMem = nullptr;
  178. particleVerts = 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 *texture)
  370. {
  371. Object::AutoRelease imagerelease(this->texture);
  372. this->texture = texture;
  373. if (texture)
  374. texture->retain();
  375. }
  376. Texture *ParticleSystem::getTexture() const
  377. {
  378. return texture;
  379. }
  380. void ParticleSystem::setInsertMode(InsertMode mode)
  381. {
  382. insertMode = mode;
  383. }
  384. ParticleSystem::InsertMode ParticleSystem::getInsertMode() const
  385. {
  386. return insertMode;
  387. }
  388. void ParticleSystem::setEmissionRate(float rate)
  389. {
  390. if (rate < 0.0f)
  391. throw love::Exception("Invalid emission rate");
  392. emissionRate = rate;
  393. }
  394. float ParticleSystem::getEmissionRate() const
  395. {
  396. return emissionRate;
  397. }
  398. void ParticleSystem::setEmitterLifetime(float life)
  399. {
  400. this->life = lifetime = life;
  401. }
  402. float ParticleSystem::getEmitterLifetime() const
  403. {
  404. return lifetime;
  405. }
  406. void ParticleSystem::setParticleLifetime(float min, float max)
  407. {
  408. particleLifeMin = min;
  409. if (max == 0)
  410. particleLifeMax = min;
  411. else
  412. particleLifeMax = max;
  413. }
  414. void ParticleSystem::getParticleLifetime(float *min, float *max) const
  415. {
  416. if (min)
  417. *min = particleLifeMin;
  418. if (max)
  419. *max = particleLifeMax;
  420. }
  421. void ParticleSystem::setPosition(float x, float y)
  422. {
  423. position = love::Vector(x, y);
  424. prevPosition = position;
  425. }
  426. const love::Vector &ParticleSystem::getPosition() const
  427. {
  428. return position;
  429. }
  430. void ParticleSystem::moveTo(float x, float y)
  431. {
  432. position = love::Vector(x, y);
  433. }
  434. void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
  435. {
  436. areaSpread = love::Vector(x, y);
  437. areaSpreadDistribution = distribution;
  438. }
  439. ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
  440. {
  441. return areaSpreadDistribution;
  442. }
  443. const love::Vector &ParticleSystem::getAreaSpreadParameters() const
  444. {
  445. return areaSpread;
  446. }
  447. void ParticleSystem::setDirection(float direction)
  448. {
  449. this->direction = direction;
  450. }
  451. float ParticleSystem::getDirection() const
  452. {
  453. return direction;
  454. }
  455. void ParticleSystem::setSpread(float spread)
  456. {
  457. this->spread = spread;
  458. }
  459. float ParticleSystem::getSpread() const
  460. {
  461. return spread;
  462. }
  463. void ParticleSystem::setSpeed(float speed)
  464. {
  465. speedMin = speedMax = speed;
  466. }
  467. void ParticleSystem::setSpeed(float min, float max)
  468. {
  469. speedMin = min;
  470. speedMax = max;
  471. }
  472. void ParticleSystem::getSpeed(float *min, float *max) const
  473. {
  474. if (min)
  475. *min = speedMin;
  476. if (max)
  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. if (min)
  492. *min = linearAccelerationMin;
  493. if (max)
  494. *max = linearAccelerationMax;
  495. }
  496. void ParticleSystem::setRadialAcceleration(float acceleration)
  497. {
  498. radialAccelerationMin = radialAccelerationMax = acceleration;
  499. }
  500. void ParticleSystem::setRadialAcceleration(float min, float max)
  501. {
  502. radialAccelerationMin = min;
  503. radialAccelerationMax = max;
  504. }
  505. void ParticleSystem::getRadialAcceleration(float *min, float *max) const
  506. {
  507. if (min)
  508. *min = radialAccelerationMin;
  509. if (max)
  510. *max = radialAccelerationMax;
  511. }
  512. void ParticleSystem::setTangentialAcceleration(float acceleration)
  513. {
  514. tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
  515. }
  516. void ParticleSystem::setTangentialAcceleration(float min, float max)
  517. {
  518. tangentialAccelerationMin = min;
  519. tangentialAccelerationMax = max;
  520. }
  521. void ParticleSystem::getTangentialAcceleration(float *min, float *max) const
  522. {
  523. if (min)
  524. *min = tangentialAccelerationMin;
  525. if (max)
  526. *max = tangentialAccelerationMax;
  527. }
  528. void ParticleSystem::setSize(float size)
  529. {
  530. sizes.resize(1);
  531. sizes[0] = size;
  532. }
  533. void ParticleSystem::setSizes(const std::vector<float> &newSizes)
  534. {
  535. sizes = newSizes;
  536. }
  537. const std::vector<float> &ParticleSystem::getSizes() const
  538. {
  539. return sizes;
  540. }
  541. void ParticleSystem::setSizeVariation(float variation)
  542. {
  543. sizeVariation = variation;
  544. }
  545. float ParticleSystem::getSizeVariation() const
  546. {
  547. return sizeVariation;
  548. }
  549. void ParticleSystem::setRotation(float rotation)
  550. {
  551. rotationMin = rotationMax = rotation;
  552. }
  553. void ParticleSystem::setRotation(float min, float max)
  554. {
  555. rotationMin = min;
  556. rotationMax = max;
  557. }
  558. void ParticleSystem::getRotation(float *min, float *max) const
  559. {
  560. if (min)
  561. *min = rotationMin;
  562. if (max)
  563. *max = rotationMax;
  564. }
  565. void ParticleSystem::setSpin(float spin)
  566. {
  567. spinStart = spin;
  568. spinEnd = spin;
  569. }
  570. void ParticleSystem::setSpin(float start, float end)
  571. {
  572. spinStart = start;
  573. spinEnd = end;
  574. }
  575. void ParticleSystem::getSpin(float *start, float *end) const
  576. {
  577. if (start)
  578. *start = spinStart;
  579. if (end)
  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. offsetX = x;
  593. offsetY = y;
  594. }
  595. love::Vector ParticleSystem::getOffset() const
  596. {
  597. return love::Vector(offsetX, offsetY);
  598. }
  599. void ParticleSystem::setColor(const Color &color)
  600. {
  601. colors.resize(1);
  602. colors[0] = colorToFloat(color);
  603. }
  604. void ParticleSystem::setColor(const std::vector<Color> &newColors)
  605. {
  606. colors.resize(newColors.size());
  607. for (size_t i = 0; i < newColors.size(); ++i)
  608. colors[i] = colorToFloat(newColors[i]);
  609. }
  610. std::vector<Color> ParticleSystem::getColor() const
  611. {
  612. // The particle system stores colors as floats...
  613. std::vector<Color> ncolors(colors.size());
  614. for (size_t i = 0; i < colors.size(); ++i)
  615. {
  616. ncolors[i].r = (unsigned char) (colors[i].r * 255);
  617. ncolors[i].g = (unsigned char) (colors[i].g * 255);
  618. ncolors[i].b = (unsigned char) (colors[i].b * 255);
  619. ncolors[i].a = (unsigned char) (colors[i].a * 255);
  620. }
  621. return ncolors;
  622. }
  623. void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
  624. {
  625. for (Quad *quad : newQuads)
  626. quad->retain();
  627. for (Quad *quad : quads)
  628. quad->release();
  629. quads = newQuads;
  630. }
  631. void ParticleSystem::setQuads()
  632. {
  633. for (Quad *quad : quads)
  634. quad->release();
  635. quads.clear();
  636. }
  637. const std::vector<Quad *> &ParticleSystem::getQuads() const
  638. {
  639. return quads;
  640. }
  641. void ParticleSystem::setRelativeRotation(bool enable)
  642. {
  643. relativeRotation = enable;
  644. }
  645. bool ParticleSystem::hasRelativeRotation() const
  646. {
  647. return relativeRotation;
  648. }
  649. uint32 ParticleSystem::getCount() const
  650. {
  651. return activeParticles;
  652. }
  653. void ParticleSystem::start()
  654. {
  655. active = true;
  656. }
  657. void ParticleSystem::stop()
  658. {
  659. active = false;
  660. life = lifetime;
  661. emitCounter = 0;
  662. }
  663. void ParticleSystem::pause()
  664. {
  665. active = false;
  666. }
  667. void ParticleSystem::reset()
  668. {
  669. if (pMem == nullptr)
  670. return;
  671. pFree = pMem;
  672. pHead = nullptr;
  673. pTail = nullptr;
  674. activeParticles = 0;
  675. life = lifetime;
  676. emitCounter = 0;
  677. }
  678. void ParticleSystem::emit(uint32 num)
  679. {
  680. if (!active)
  681. return;
  682. num = std::min(num, maxParticles - activeParticles);
  683. while(num--)
  684. addParticle(1.0f);
  685. }
  686. bool ParticleSystem::isActive() const
  687. {
  688. return active;
  689. }
  690. bool ParticleSystem::isPaused() const
  691. {
  692. return !active && life < lifetime;
  693. }
  694. bool ParticleSystem::isStopped() const
  695. {
  696. return !active && life >= lifetime;
  697. }
  698. bool ParticleSystem::isEmpty() const
  699. {
  700. return activeParticles == 0;
  701. }
  702. bool ParticleSystem::isFull() const
  703. {
  704. return activeParticles == maxParticles;
  705. }
  706. void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
  707. {
  708. uint32 pCount = getCount();
  709. if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr)
  710. return;
  711. Color curcolor = gl.getColor();
  712. static Matrix t;
  713. t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
  714. OpenGL::TempTransform transform(gl);
  715. transform.get() *= t;
  716. const Vertex *textureVerts = texture->getVertices();
  717. Vertex *pVerts = particleVerts;
  718. Particle *p = pHead;
  719. bool useQuads = !quads.empty();
  720. // set the vertex data for each particle (transformation, texcoords, color)
  721. while (p)
  722. {
  723. if (useQuads)
  724. textureVerts = quads[p->quadIndex]->getVertices();
  725. // particle vertices are image vertices transformed by particle information
  726. t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
  727. t.transform(pVerts, textureVerts, 4);
  728. // set the texture coordinate and color data for particle vertices
  729. for (int v = 0; v < 4; v++)
  730. {
  731. pVerts[v].s = textureVerts[v].s;
  732. pVerts[v].t = textureVerts[v].t;
  733. // particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255)
  734. pVerts[v].r = (unsigned char) (p->color.r*255);
  735. pVerts[v].g = (unsigned char) (p->color.g*255);
  736. pVerts[v].b = (unsigned char) (p->color.b*255);
  737. pVerts[v].a = (unsigned char) (p->color.a*255);
  738. }
  739. pVerts += 4;
  740. p = p->next;
  741. }
  742. texture->predraw();
  743. glEnableClientState(GL_COLOR_ARRAY);
  744. glEnableClientState(GL_VERTEX_ARRAY);
  745. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  746. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid *) &particleVerts[0].r);
  747. glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].x);
  748. glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].s);
  749. gl.prepareDraw();
  750. glDrawArrays(GL_QUADS, 0, pCount * 4);
  751. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  752. glDisableClientState(GL_VERTEX_ARRAY);
  753. glDisableClientState(GL_COLOR_ARRAY);
  754. texture->postdraw();
  755. gl.setColor(curcolor);
  756. }
  757. void ParticleSystem::update(float dt)
  758. {
  759. if (pMem == nullptr || dt == 0.0f)
  760. return;
  761. // Traverse all particles and update.
  762. Particle *p = pHead;
  763. while (p)
  764. {
  765. // Decrease lifespan.
  766. p->life -= dt;
  767. if (p->life <= 0)
  768. p = removeParticle(p);
  769. else
  770. {
  771. // Temp variables.
  772. love::Vector radial, tangential;
  773. love::Vector ppos(p->position[0], p->position[1]);
  774. // Get vector from particle center to particle.
  775. radial = ppos - p->origin;
  776. radial.normalize();
  777. tangential = radial;
  778. // Resize radial acceleration.
  779. radial *= p->radialAcceleration;
  780. // Calculate tangential acceleration.
  781. {
  782. float a = tangential.getX();
  783. tangential.setX(-tangential.getY());
  784. tangential.setY(a);
  785. }
  786. // Resize tangential.
  787. tangential *= p->tangentialAcceleration;
  788. // Update velocity.
  789. p->velocity += (radial + tangential + p->linearAcceleration) * dt;
  790. // Modify position.
  791. ppos += p->velocity * dt;
  792. p->position[0] = ppos.getX();
  793. p->position[1] = ppos.getY();
  794. const float t = 1.0f - p->life / p->lifetime;
  795. // Rotate.
  796. p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt;
  797. p->angle = p->rotation;
  798. if (relativeRotation)
  799. p->angle += atan2f(p->velocity.y, p->velocity.x);
  800. // Change size according to given intervals:
  801. // i = 0 1 2 3 n-1
  802. // |-------|-------|------|--- ... ---|
  803. // t = 0 1/(n-1) 3/(n-1) 1
  804. //
  805. // `s' is the interpolation variable scaled to the current
  806. // interval width, e.g. if n = 5 and t = 0.3, then the current
  807. // indices are 1,2 and s = 0.3 - 0.25 = 0.05
  808. float s = p->sizeOffset + t * p->sizeIntervalSize; // size variation
  809. s *= (float)(sizes.size() - 1); // 0 <= s < sizes.size()
  810. size_t i = (size_t)s;
  811. size_t k = (i == sizes.size() - 1) ? i : i + 1; // boundary check (prevents failing on t = 1.0f)
  812. s -= (float)i; // transpose s to be in interval [0:1]: i <= s < i + 1 ~> 0 <= s < 1
  813. p->size = sizes[i] * (1.0f - s) + sizes[k] * s;
  814. // Update color according to given intervals (as above)
  815. s = t * (float)(colors.size() - 1);
  816. i = (size_t)s;
  817. k = (i == colors.size() - 1) ? i : i + 1;
  818. s -= (float)i; // 0 <= s <= 1
  819. p->color = colors[i] * (1.0f - s) + colors[k] * s;
  820. // Update the quad index.
  821. k = quads.size();
  822. if (k > 0)
  823. {
  824. s = t * (float) k; // [0:numquads-1] (clamped below)
  825. i = (s > 0.0f) ? (size_t) s : 0;
  826. p->quadIndex = (i < k) ? i : k - 1;
  827. }
  828. // Next particle.
  829. p = p->next;
  830. }
  831. }
  832. // Make some more particles.
  833. if (active)
  834. {
  835. float rate = 1.0f / emissionRate; // the amount of time between each particle emit
  836. emitCounter += dt;
  837. float total = emitCounter - rate;
  838. while (emitCounter > rate)
  839. {
  840. addParticle(1.0f - (emitCounter - rate) / total);
  841. emitCounter -= rate;
  842. }
  843. /*int particles = (int)(emissionRate * dt);
  844. for (int i = 0; i != particles; i++)
  845. add();*/
  846. life -= dt;
  847. if (lifetime != -1 && life < 0)
  848. stop();
  849. }
  850. prevPosition = position;
  851. }
  852. bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
  853. {
  854. return distributions.find(in, out);
  855. }
  856. bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
  857. {
  858. return distributions.find(in, out);
  859. }
  860. bool ParticleSystem::getConstant(const char *in, InsertMode &out)
  861. {
  862. return insertModes.find(in, out);
  863. }
  864. bool ParticleSystem::getConstant(InsertMode in, const char *&out)
  865. {
  866. return insertModes.find(in, out);
  867. }
  868. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] =
  869. {
  870. { "none", ParticleSystem::DISTRIBUTION_NONE },
  871. { "uniform", ParticleSystem::DISTRIBUTION_UNIFORM },
  872. { "normal", ParticleSystem::DISTRIBUTION_NORMAL },
  873. };
  874. StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
  875. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM>::Entry ParticleSystem::insertModesEntries[] =
  876. {
  877. { "top", ParticleSystem::INSERT_MODE_TOP },
  878. { "bottom", ParticleSystem::INSERT_MODE_BOTTOM },
  879. { "random", ParticleSystem::INSERT_MODE_RANDOM },
  880. };
  881. StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM> ParticleSystem::insertModes(ParticleSystem::insertModesEntries, sizeof(ParticleSystem::insertModesEntries));
  882. } // opengl
  883. } // graphics
  884. } // love