ParticleSystem.cpp 20 KB

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