/src/renderer/particles.cpp

https://bitbucket.org/vivkin/gam3b00bs/ · C++ · 324 lines · 237 code · 72 blank · 15 comment · 21 complexity · fe0ea52717149a3fe347fca25221fd91 MD5 · raw file

  1. #include "particles.h"
  2. #include "renderer/device.h"
  3. static const camera_t *s_camera = NULL;
  4. inline static float frandom()
  5. {
  6. return (float)rand() / (float)RAND_MAX;
  7. }
  8. inline static float frandom(float a)
  9. {
  10. return frandom() * a;
  11. }
  12. inline static float frandom(float a, float b)
  13. {
  14. return a + (b - a) * frandom();
  15. }
  16. // random point on sphere
  17. inline static const D3DXVECTOR3 sphrand()
  18. {
  19. float u = frandom(2.0f * 3.14159265f);
  20. float h = frandom(2.0f) - 1.0f;
  21. float r = sqrtf(1.0f - h * h);
  22. return D3DXVECTOR3(cosf(u) * r, sinf(u) * r, h);
  23. }
  24. inline static void particle_update(particle_emitter_t *emitter, uint32_t i, float dt, const D3DXVECTOR3& v0, const D3DXVECTOR3& v1)
  25. {
  26. ASSERT(emitter);
  27. particle_t *particle = emitter->particles + i;
  28. float t = particle->life / emitter->life[1], size = particle->size / 2.0f;
  29. particle->position += particle->direction * dt;
  30. particle->vertices[0].x = particle->position.x + size * v0.x;
  31. particle->vertices[0].y = particle->position.y + size * v0.y;
  32. particle->vertices[0].z = particle->position.z + size * v0.z;
  33. particle->vertices[1].x = particle->position.x - size * v1.x;
  34. particle->vertices[1].y = particle->position.y - size * v1.y;
  35. particle->vertices[1].z = particle->position.z - size * v1.z;
  36. particle->vertices[2].x = particle->position.x - size * v0.x;
  37. particle->vertices[2].y = particle->position.y - size * v0.y;
  38. particle->vertices[2].z = particle->position.z - size * v0.z;
  39. particle->vertices[3].x = particle->position.x + size * v1.x;
  40. particle->vertices[3].y = particle->position.y + size * v1.y;
  41. particle->vertices[3].z = particle->position.z + size * v1.z;
  42. #define COLOR_LERP3(b, a, t) D3DCOLOR_ARGB(\
  43. (int)(255 * t), \
  44. (int)(255 * (a[0] + (b[0] - a[0]) * t)), \
  45. (int)(255 * (a[1] + (b[1] - a[1]) * t)), \
  46. (int)(255 * (a[2] + (b[2] - a[2]) * t)))
  47. particle->vertices[0].color = particle->vertices[1].color =
  48. particle->vertices[2].color = particle->vertices[3].color =
  49. COLOR_LERP3(emitter->color[0], emitter->color[1], t);
  50. #undef COLOR_LERP3
  51. }
  52. inline static void particle_remove(particle_emitter_t *emitter, uint32_t i)
  53. {
  54. // call particle_remove() only from particle_emitter_update()
  55. //ASSERT(emitter);
  56. //ASSERT(i < emitter->particles_count);
  57. // i is always less than emitter->particles_count
  58. // so emitter->particles_count is alwys greater than 0
  59. //if (emitter->particles_count == 0)
  60. // return;
  61. uint32_t j = --emitter->particles_count;
  62. if (i != j)
  63. emitter->particles[i] = emitter->particles[j];
  64. //memcpy(emitter->particles + i, emitter->particles + j, sizeof(particle_t));
  65. }
  66. inline static void particle_spawn(particle_emitter_t *emitter)
  67. {
  68. ASSERT(emitter);
  69. if (emitter->particles_count >= PARTICLES_MAX)
  70. return;
  71. particle_t *particle = emitter->particles + emitter->particles_count++;
  72. particle->position = D3DXVECTOR3(0.0f, 0.0f, 0.0f); //emitter->position;
  73. particle->direction = sphrand()
  74. //particle->direction = (emitter->direction)
  75. * frandom(emitter->speed[0], emitter->speed[1]);
  76. particle->life = frandom(emitter->life[0], emitter->life[1]);
  77. particle->size = frandom(emitter->size[0], emitter->size[1]);
  78. }
  79. static int particle_compare(const void *a, const void *b)
  80. {
  81. ASSERT(s_camera);
  82. ASSERT(a && b);
  83. const particle_t *p1 = (particle_t *)a, *p2 = (particle_t *)b;
  84. D3DXVECTOR3 d1 = p1->position - s_camera->position,
  85. d2 = p2->position - s_camera->position;
  86. return (int)(D3DXVec3LengthSq(&d2) - D3DXVec3LengthSq(&d1));
  87. }
  88. static void particle_emitter_update(particle_emitter_t *emitter, float dt, const camera_t& cam )
  89. {
  90. ASSERT(emitter);
  91. D3DXVECTOR3 view_vec = cam.position - emitter->position;
  92. D3DXVECTOR3 up(0.0f, -1.0f, 0.0f);
  93. D3DXVECTOR3 v0;
  94. D3DXVECTOR3 v1;
  95. D3DXVec3Normalize( &view_vec, &view_vec );
  96. D3DXVec3Cross(&v0, &view_vec, &up);
  97. D3DXVec3Normalize( &v0, &v0 );
  98. D3DXVec3Cross(&v1, &view_vec, &v0);
  99. D3DXVec3Normalize( &v1, &v1 );
  100. // update particles
  101. for (uint32_t i = 0; i < emitter->particles_count; ++i)
  102. {
  103. particle_update(emitter, i, dt, v0, v1);
  104. if ((emitter->particles[i].life -= dt) <= 0.0f)
  105. particle_remove(emitter, i--);
  106. }
  107. // spawn particle
  108. emitter->spawn_time -= dt;
  109. emitter->spawn_last += dt;
  110. if (emitter->spawn_time > 0.0f && emitter->spawn_last >= (1.0f / emitter->spawn_rate))
  111. {
  112. particle_spawn(emitter);
  113. emitter->spawn_last = 0.0f; // -= dt;
  114. }
  115. qsort(emitter->particles, emitter->particles_count, sizeof(particle_t), particle_compare);
  116. }
  117. static void particle_emitter_render(particle_emitter_t *emitter, LPDIRECT3DDEVICE9 device)
  118. {
  119. ASSERT(emitter);
  120. ASSERT(device);
  121. static particle_vertex_t *vertices;
  122. renderer::vbuffer_lock(emitter->visual.vb, (void **)&vertices, 0, 0);
  123. for (uint32_t i = 0; i < emitter->particles_count; ++i)
  124. {
  125. memcpy(vertices + i * 4, emitter->particles[i].vertices,
  126. sizeof(particle_vertex_t) * 4);
  127. }
  128. renderer::vbuffer_unlock(emitter->visual.vb);
  129. device->SetStreamSource(0, emitter->visual.vb->buffer, 0, sizeof(particle_vertex_t));
  130. device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0,
  131. emitter->particles_count * 4, 0, emitter->particles_count * 2);
  132. }
  133. void particle_system_create(particle_system_t *psys)
  134. {
  135. ASSERT(psys);
  136. memset(psys, 0, sizeof(particle_system_t));
  137. static const uint32_t indices_count = PARTICLES_MAX * 6;
  138. static uint32_t indices[indices_count];
  139. for (uint32_t i = 0, j = 0; i < indices_count; i += 6, j += 4)
  140. {
  141. indices[i + 0] = j + 0;
  142. indices[i + 1] = j + 2;
  143. indices[i + 2] = j + 1;
  144. indices[i + 3] = j + 0;
  145. indices[i + 4] = j + 3;
  146. indices[i + 5] = j + 2;
  147. }
  148. psys->visual.ib = renderer::ibuffer_create(IB_32BIT, sizeof(indices), (const byte *)indices);
  149. ASSERT(psys->visual.ib);
  150. psys->visual.vlayout = renderer::get_vertex_layout(VE_POSITION | VE_COLOR | VE_TEXTURE0);
  151. D3DXMatrixIdentity(&psys->visual.transform);
  152. for (uint32_t i = 0; i < PARTICLE_EMITTERS_MAX; ++i)
  153. {
  154. psys->emitters[i].visual.vb = renderer::vbuffer_create(PARTICLES_MAX
  155. * sizeof(particle_vertex_t) * 4, NULL, D3DUSAGE_DYNAMIC);
  156. ASSERT(psys->emitters[i].visual.vb);
  157. }
  158. for (uint32_t i = 0; i < PARTICLE_EMITTERS_MAX; ++i)
  159. {
  160. for (uint32_t j = 0; j < PARTICLES_MAX; ++j)
  161. {
  162. particle_t *particle = psys->emitters[i].particles + j;
  163. particle->vertices[0].u = 0.0f;
  164. particle->vertices[0].v = 1.0f;
  165. particle->vertices[1].u = 0.0f;
  166. particle->vertices[1].v = 0.0f;
  167. particle->vertices[2].u = 1.0f;
  168. particle->vertices[2].v = 0.0f;
  169. particle->vertices[3].u = 1.0f;
  170. particle->vertices[3].v = 1.0f;
  171. }
  172. }
  173. }
  174. void particle_system_add(particle_system_t *psys, const particle_desc_t *desc)
  175. {
  176. ASSERT(psys);
  177. if (psys->emitters_count >= PARTICLE_EMITTERS_MAX)
  178. return;
  179. particle_emitter_t *emitter = psys->emitters + psys->emitters_count++;
  180. emitter->particles_count = 0;
  181. emitter->spawn_last = 0.0f;
  182. emitter->visual.texture = desc->texture;
  183. emitter->position = desc->position;
  184. emitter->direction = desc->direction;
  185. emitter->spawn_rate = desc->rate;
  186. emitter->spawn_time = desc->time;
  187. memcpy(emitter->speed, desc->speed, sizeof(emitter->speed));
  188. memcpy(emitter->life, desc->life, sizeof(emitter->life));
  189. memcpy(emitter->size, desc->size, sizeof(emitter->size));
  190. memcpy(emitter->color, desc->color, sizeof(emitter->color));
  191. }
  192. inline static void emitter_remove(particle_system_t *psys, uint32_t i)
  193. {
  194. uint32_t j = --psys->emitters_count;
  195. if (i != j)
  196. psys->emitters[i] = psys->emitters[j];
  197. //memcpy(psys->emitters + i, psys->emitters + j, sizeof(particle_emitter_t));
  198. }
  199. static int emitter_compare(const void *a, const void *b)
  200. {
  201. ASSERT(s_camera);
  202. ASSERT(a && b);
  203. const particle_emitter_t *e1 = (particle_emitter_t *)a,
  204. *e2 = (particle_emitter_t *)b;
  205. D3DXVECTOR3 d1 = e1->position - s_camera->position,
  206. d2 = e2->position - s_camera->position;
  207. return (int)(D3DXVec3LengthSq(&d2) - D3DXVec3LengthSq(&d1));
  208. }
  209. void particle_system_update(particle_system_t *psys, const camera_t &camera, float dt)
  210. {
  211. ASSERT(psys);
  212. s_camera = &camera;
  213. for (uint32_t i = 0; i < psys->emitters_count; ++i)
  214. {
  215. particle_emitter_update(psys->emitters + i, dt, camera);
  216. // remove emitter
  217. if (psys->emitters[i].particles_count == 0)
  218. emitter_remove(psys, i--);
  219. }
  220. qsort(psys->emitters, psys->emitters_count, sizeof(particle_emitter_t), emitter_compare);
  221. }
  222. void particle_system_render(particle_system_t *psys, const camera_t &camera, LPDIRECT3DDEVICE9 device)
  223. {
  224. ASSERT(psys);
  225. ASSERT(device);
  226. device->SetRenderState(D3DRS_LIGHTING, FALSE);
  227. device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
  228. device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  229. device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  230. // D3DBLEND_INVSRCALPHA or D3DBLEND_ONE
  231. device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  232. device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  233. device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  234. device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  235. device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  236. device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  237. device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  238. D3DXMATRIX world, inverted;
  239. D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  240. device->SetVertexDeclaration(psys->visual.vlayout->decl);
  241. device->SetIndices(psys->visual.ib->buffer);
  242. for (uint32_t i = 0; i < psys->emitters_count; ++i)
  243. {
  244. D3DXMatrixTranslation( &world, psys->emitters[i].position.x, psys->emitters[i].position.y, psys->emitters[i].position.z );
  245. device->SetTransform(D3DTS_WORLD, &world);
  246. device->SetTexture(0, psys->emitters[i].visual.texture->texture);
  247. particle_emitter_render(psys->emitters + i, device);
  248. }
  249. device->SetRenderState(D3DRS_LIGHTING, TRUE);
  250. device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
  251. device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  252. }