ParticleSystem.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /**
  2. * Copyright (c) 2006-2009 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. #include "ParticleSystem.h"
  21. #include <SDL_opengl.h>
  22. #include <cmath>
  23. #include <cstdlib>
  24. #include <cstring>
  25. namespace love
  26. {
  27. namespace graphics
  28. {
  29. namespace opengl
  30. {
  31. float calculate_variation(float inner, float outer, float var)
  32. {
  33. float low = inner - (outer/2.0f)*var;
  34. float high = inner + (outer/2.0f)*var;
  35. float r = (rand() / (float(RAND_MAX)+1));
  36. return low*(1-r)+high*r;
  37. }
  38. ParticleSystem::ParticleSystem(Image * sprite, unsigned int buffer) : pStart(0), pLast(0), pEnd(0), active(true), emissionRate(0),
  39. emitCounter(0), lifetime(-1), life(0), particleLifeMin(0), particleLifeMax(0),
  40. direction(0), spread(0), relative(false), speedMin(0), speedMax(0), gravityMin(0),
  41. gravityMax(0), radialAccelerationMin(0), radialAccelerationMax(0),
  42. tangentialAccelerationMin(0), tangentialAccelerationMax(0),
  43. sizeStart(1), sizeEnd(1), sizeVariation(0), rotationMin(0), rotationMax(0),
  44. spinStart(0), spinEnd(0), spinVariation(0), offsetX(sprite->getWidth()*0.5f),
  45. offsetY(sprite->getHeight()*0.5f)
  46. {
  47. this->sprite = sprite;
  48. sprite->retain();
  49. memset(colorStart, 255, 4);
  50. memset(colorEnd, 255, 4);
  51. setBufferSize(buffer);
  52. }
  53. ParticleSystem::~ParticleSystem()
  54. {
  55. if(this->sprite != 0)
  56. {
  57. this->sprite->release();
  58. this->sprite = 0;
  59. }
  60. if(pStart != 0)
  61. delete [] pStart;
  62. }
  63. void ParticleSystem::add()
  64. {
  65. if(isFull()) return;
  66. float min,max;
  67. min = particleLifeMin;
  68. max = particleLifeMax;
  69. if(min == max)
  70. pLast->life = min;
  71. else
  72. pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  73. pLast->lifetime = pLast->life;
  74. pLast->position[0] = position.getX();
  75. pLast->position[1] = position.getY();
  76. min = direction - spread/2.0f;
  77. max = direction + spread/2.0f;
  78. pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  79. min = speedMin;
  80. max = speedMax;
  81. float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  82. pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
  83. pLast->speed *= speed;
  84. min = gravityMin;
  85. max = gravityMax;
  86. pLast->gravity = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  87. min = radialAccelerationMin;
  88. max = radialAccelerationMax;
  89. pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  90. min = tangentialAccelerationMin;
  91. max = tangentialAccelerationMax;
  92. pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
  93. pLast->sizeStart = calculate_variation(sizeStart, sizeEnd, sizeVariation);
  94. pLast->sizeEnd = calculate_variation(sizeEnd, sizeStart, sizeVariation);
  95. pLast->size = pLast->sizeStart;
  96. min = rotationMin;
  97. max = rotationMax;
  98. pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
  99. pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
  100. pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;;
  101. pLast->color[0] = (float)colorStart[0] / 255;
  102. pLast->color[1] = (float)colorStart[1] / 255;
  103. pLast->color[2] = (float)colorStart[2] / 255;
  104. pLast->color[3] = (float)colorStart[3] / 255;
  105. pLast++;
  106. }
  107. void ParticleSystem::remove(particle * p)
  108. {
  109. if(!isEmpty())
  110. {
  111. *p = *(--pLast);
  112. }
  113. }
  114. void ParticleSystem::setSprite(Image * image)
  115. {
  116. if(this->sprite != 0)
  117. {
  118. this->sprite->release();
  119. this->sprite = 0;
  120. }
  121. this->sprite = image;
  122. }
  123. void ParticleSystem::setBufferSize(unsigned int size)
  124. {
  125. // delete previous data
  126. delete [] pStart;
  127. pLast = pStart = new particle[size];
  128. pEnd = pStart + size;
  129. }
  130. void ParticleSystem::setEmissionRate(int rate)
  131. {
  132. emissionRate = rate;
  133. }
  134. void ParticleSystem::setLifetime(float life)
  135. {
  136. this->life = lifetime = life;
  137. }
  138. void ParticleSystem::setParticleLife(float min, float max)
  139. {
  140. particleLifeMin = min;
  141. if(max == 0)
  142. particleLifeMax = min;
  143. else
  144. particleLifeMax = max;
  145. }
  146. void ParticleSystem::setPosition(float x, float y)
  147. {
  148. position = love::Vector(x, y);
  149. }
  150. void ParticleSystem::setDirection(float direction)
  151. {
  152. this->direction = direction;
  153. }
  154. void ParticleSystem::setSpread(float spread)
  155. {
  156. this->spread = spread;
  157. }
  158. void ParticleSystem::setRelativeDirection(bool relative)
  159. {
  160. this->relative = relative;
  161. }
  162. void ParticleSystem::setSpeed(float speed)
  163. {
  164. speedMin = speedMax = speed;
  165. }
  166. void ParticleSystem::setSpeed(float min, float max)
  167. {
  168. speedMin = min;
  169. speedMax = max;
  170. }
  171. void ParticleSystem::setGravity(float gravity)
  172. {
  173. gravityMin = gravityMax = gravity;
  174. }
  175. void ParticleSystem::setGravity(float min, float max)
  176. {
  177. gravityMin = min;
  178. gravityMax = max;
  179. }
  180. void ParticleSystem::setRadialAcceleration(float acceleration)
  181. {
  182. radialAccelerationMin = radialAccelerationMax = acceleration;
  183. }
  184. void ParticleSystem::setRadialAcceleration(float min, float max)
  185. {
  186. radialAccelerationMin = min;
  187. radialAccelerationMax = max;
  188. }
  189. void ParticleSystem::setTangentialAcceleration(float acceleration)
  190. {
  191. tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
  192. }
  193. void ParticleSystem::setTangentialAcceleration(float min, float max)
  194. {
  195. tangentialAccelerationMin = min;
  196. tangentialAccelerationMax = max;
  197. }
  198. void ParticleSystem::setSize(float size)
  199. {
  200. sizeStart = size;
  201. sizeEnd = size;
  202. }
  203. void ParticleSystem::setSize(float start, float end)
  204. {
  205. sizeStart = start;
  206. sizeEnd = end;
  207. }
  208. void ParticleSystem::setSize(float start, float end, float variation)
  209. {
  210. sizeStart = start;
  211. sizeEnd = end;
  212. sizeVariation = variation;
  213. }
  214. void ParticleSystem::setSizeVariation(float variation)
  215. {
  216. sizeVariation = variation;
  217. }
  218. void ParticleSystem::setRotation(float rotation)
  219. {
  220. rotationMin = rotationMax = rotation;
  221. }
  222. void ParticleSystem::setRotation(float min, float max)
  223. {
  224. rotationMin = min;
  225. rotationMax = max;
  226. }
  227. void ParticleSystem::setSpin(float spin)
  228. {
  229. spinStart = spin;
  230. spinEnd = spin;
  231. }
  232. void ParticleSystem::setSpin(float start, float end)
  233. {
  234. spinStart = start;
  235. spinEnd = end;
  236. }
  237. void ParticleSystem::setSpin(float start, float end, float variation)
  238. {
  239. spinStart = start;
  240. spinEnd = end;
  241. spinVariation = variation;
  242. }
  243. void ParticleSystem::setSpinVariation(float variation)
  244. {
  245. spinVariation = variation;
  246. }
  247. void ParticleSystem::setColor(unsigned char * color)
  248. {
  249. memcpy(colorStart, color, 4);
  250. memcpy(colorEnd, color, 4);
  251. }
  252. void ParticleSystem::setColor(unsigned char * start, unsigned char * end)
  253. {
  254. memcpy(colorStart, start, 4);
  255. memcpy(colorEnd, end, 4);
  256. }
  257. void ParticleSystem::setOffset(float x, float y)
  258. {
  259. offsetX = x;
  260. offsetY = y;
  261. }
  262. float ParticleSystem::getX() const
  263. {
  264. return position.getX();
  265. }
  266. float ParticleSystem::getY() const
  267. {
  268. return position.getY();
  269. }
  270. float ParticleSystem::getDirection() const
  271. {
  272. return direction;
  273. }
  274. float ParticleSystem::getSpread() const
  275. {
  276. return spread;
  277. }
  278. float ParticleSystem::getOffsetX() const
  279. {
  280. return offsetX;
  281. }
  282. float ParticleSystem::getOffsetY() const
  283. {
  284. return offsetY;
  285. }
  286. int ParticleSystem::count() const
  287. {
  288. return (int)(pLast - pStart);
  289. }
  290. void ParticleSystem::start()
  291. {
  292. active = true;
  293. }
  294. void ParticleSystem::stop()
  295. {
  296. active = false;
  297. life = lifetime;
  298. emitCounter = 0;
  299. }
  300. void ParticleSystem::pause()
  301. {
  302. active = false;
  303. }
  304. void ParticleSystem::reset()
  305. {
  306. pLast = pStart;
  307. life = lifetime;
  308. emitCounter = 0;
  309. }
  310. bool ParticleSystem::isActive() const
  311. {
  312. return active;
  313. }
  314. bool ParticleSystem::isEmpty() const
  315. {
  316. return pStart == pLast;
  317. }
  318. bool ParticleSystem::isFull() const
  319. {
  320. return pLast == pEnd;
  321. }
  322. void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy) const
  323. {
  324. if(sprite == 0) return; // just in case of failure
  325. glPushMatrix();
  326. glPushAttrib(GL_CURRENT_BIT);
  327. glTranslatef(x, y, 0);
  328. glRotatef(angle, 0, 0, 1.0f);
  329. glScalef(sx, sy, 1.0f);
  330. glTranslatef( ox, oy, 0);
  331. particle * p = pStart;
  332. while(p != pLast)
  333. {
  334. glPushMatrix();
  335. glColor4f(p->color[0],p->color[1],p->color[2],p->color[3]);
  336. glTranslatef(p->position[0],p->position[1],0.0f);
  337. glRotatef(p->rotation * 57.29578f, 0.0f, 0.0f, 1.0f); // rad * (180 / pi)
  338. glScalef(p->size,p->size,1.0f);
  339. glTranslatef(-offsetX,-offsetY,0.0f);
  340. sprite->draw(0,0, 0, 1, 1, 0, 0);
  341. glPopMatrix();
  342. p++;
  343. }
  344. glPopAttrib();
  345. glPopMatrix();
  346. }
  347. void ParticleSystem::update(float dt)
  348. {
  349. // Traverse all particles and update.
  350. particle * p = pStart;
  351. // Make some more particles.
  352. if(active)
  353. {
  354. float rate = 1.0f / emissionRate; // the amount of time between each particle emit
  355. emitCounter += dt;
  356. while(emitCounter > rate)
  357. {
  358. add();
  359. emitCounter -= rate;
  360. }
  361. /*int particles = (int)(emissionRate * dt);
  362. for(int i = 0; i != particles; i++)
  363. add();*/
  364. life -= dt;
  365. if(lifetime != -1 && life < 0)
  366. stop();
  367. }
  368. while(p != pLast)
  369. {
  370. // Decrease lifespan.
  371. p->life -= dt;
  372. if(p->life > 0)
  373. {
  374. // Temp variables.
  375. love::Vector radial, tangential, gravity(0, p->gravity);
  376. love::Vector ppos(p->position[0], p->position[1]);
  377. // Get vector from particle center to particle.
  378. radial = ppos - position;
  379. radial.normalize();
  380. tangential = radial;
  381. // Resize radial acceleration.
  382. radial *= p->radialAcceleration;
  383. // Calculate tangential acceleration.
  384. {
  385. float a = tangential.getX();
  386. tangential.setX(-tangential.getY());
  387. tangential.setY(a);
  388. }
  389. // Resize tangential.
  390. tangential *= p->tangentialAcceleration;
  391. // Update position.
  392. p->speed += (radial+tangential+gravity)*dt;
  393. // Modify position.
  394. ppos += p->speed * dt;
  395. p->position[0] = ppos.getX();
  396. p->position[1] = ppos.getY();
  397. const float t = p->life / p->lifetime;
  398. // Change size.
  399. p->size = p->sizeEnd - ((p->sizeEnd - p->sizeStart) * t);
  400. // Rotate.
  401. p->rotation += (p->spinStart*(1-t) + p->spinEnd*t)*dt;
  402. // Update color.
  403. p->color[0] = (float)(colorEnd[0]*(1.0f-t) + colorStart[0] * t)/255.0f;
  404. p->color[1] = (float)(colorEnd[1]*(1.0f-t) + colorStart[1] * t)/255.0f;
  405. p->color[2] = (float)(colorEnd[2]*(1.0f-t) + colorStart[2] * t)/255.0f;
  406. p->color[3] = (float)(colorEnd[3]*(1.0f-t) + colorStart[3] * t)/255.0f;
  407. // Next particle.
  408. p++;
  409. }
  410. else
  411. {
  412. remove(p);
  413. if(p >= pLast)
  414. return;
  415. } // else
  416. } // while
  417. }
  418. } // opengl
  419. } // graphics
  420. } // love