/src/renderer/particles.cpp
https://bitbucket.org/vivkin/gam3b00bs/ · C++ · 324 lines · 237 code · 72 blank · 15 comment · 21 complexity · fe0ea52717149a3fe347fca25221fd91 MD5 · raw file
- #include "particles.h"
- #include "renderer/device.h"
-
- static const camera_t *s_camera = NULL;
-
- inline static float frandom()
- {
- return (float)rand() / (float)RAND_MAX;
- }
-
- inline static float frandom(float a)
- {
- return frandom() * a;
- }
-
- inline static float frandom(float a, float b)
- {
- return a + (b - a) * frandom();
- }
-
- // random point on sphere
- inline static const D3DXVECTOR3 sphrand()
- {
- float u = frandom(2.0f * 3.14159265f);
- float h = frandom(2.0f) - 1.0f;
- float r = sqrtf(1.0f - h * h);
- return D3DXVECTOR3(cosf(u) * r, sinf(u) * r, h);
- }
-
- inline static void particle_update(particle_emitter_t *emitter, uint32_t i, float dt, const D3DXVECTOR3& v0, const D3DXVECTOR3& v1)
- {
- ASSERT(emitter);
-
- particle_t *particle = emitter->particles + i;
- float t = particle->life / emitter->life[1], size = particle->size / 2.0f;
-
- particle->position += particle->direction * dt;
-
- particle->vertices[0].x = particle->position.x + size * v0.x;
- particle->vertices[0].y = particle->position.y + size * v0.y;
- particle->vertices[0].z = particle->position.z + size * v0.z;
- particle->vertices[1].x = particle->position.x - size * v1.x;
- particle->vertices[1].y = particle->position.y - size * v1.y;
- particle->vertices[1].z = particle->position.z - size * v1.z;
- particle->vertices[2].x = particle->position.x - size * v0.x;
- particle->vertices[2].y = particle->position.y - size * v0.y;
- particle->vertices[2].z = particle->position.z - size * v0.z;
- particle->vertices[3].x = particle->position.x + size * v1.x;
- particle->vertices[3].y = particle->position.y + size * v1.y;
- particle->vertices[3].z = particle->position.z + size * v1.z;
-
- #define COLOR_LERP3(b, a, t) D3DCOLOR_ARGB(\
- (int)(255 * t), \
- (int)(255 * (a[0] + (b[0] - a[0]) * t)), \
- (int)(255 * (a[1] + (b[1] - a[1]) * t)), \
- (int)(255 * (a[2] + (b[2] - a[2]) * t)))
-
- particle->vertices[0].color = particle->vertices[1].color =
- particle->vertices[2].color = particle->vertices[3].color =
- COLOR_LERP3(emitter->color[0], emitter->color[1], t);
-
- #undef COLOR_LERP3
- }
-
- inline static void particle_remove(particle_emitter_t *emitter, uint32_t i)
- {
- // call particle_remove() only from particle_emitter_update()
-
- //ASSERT(emitter);
- //ASSERT(i < emitter->particles_count);
-
- // i is always less than emitter->particles_count
- // so emitter->particles_count is alwys greater than 0
-
- //if (emitter->particles_count == 0)
- // return;
-
- uint32_t j = --emitter->particles_count;
-
- if (i != j)
- emitter->particles[i] = emitter->particles[j];
- //memcpy(emitter->particles + i, emitter->particles + j, sizeof(particle_t));
- }
-
- inline static void particle_spawn(particle_emitter_t *emitter)
- {
- ASSERT(emitter);
-
- if (emitter->particles_count >= PARTICLES_MAX)
- return;
-
- particle_t *particle = emitter->particles + emitter->particles_count++;
-
- particle->position = D3DXVECTOR3(0.0f, 0.0f, 0.0f); //emitter->position;
- particle->direction = sphrand()
- //particle->direction = (emitter->direction)
- * frandom(emitter->speed[0], emitter->speed[1]);
- particle->life = frandom(emitter->life[0], emitter->life[1]);
- particle->size = frandom(emitter->size[0], emitter->size[1]);
- }
-
- static int particle_compare(const void *a, const void *b)
- {
- ASSERT(s_camera);
- ASSERT(a && b);
-
- const particle_t *p1 = (particle_t *)a, *p2 = (particle_t *)b;
-
- D3DXVECTOR3 d1 = p1->position - s_camera->position,
- d2 = p2->position - s_camera->position;
-
- return (int)(D3DXVec3LengthSq(&d2) - D3DXVec3LengthSq(&d1));
- }
-
- static void particle_emitter_update(particle_emitter_t *emitter, float dt, const camera_t& cam )
- {
- ASSERT(emitter);
-
- D3DXVECTOR3 view_vec = cam.position - emitter->position;
- D3DXVECTOR3 up(0.0f, -1.0f, 0.0f);
- D3DXVECTOR3 v0;
- D3DXVECTOR3 v1;
- D3DXVec3Normalize( &view_vec, &view_vec );
- D3DXVec3Cross(&v0, &view_vec, &up);
- D3DXVec3Normalize( &v0, &v0 );
- D3DXVec3Cross(&v1, &view_vec, &v0);
- D3DXVec3Normalize( &v1, &v1 );
-
- // update particles
- for (uint32_t i = 0; i < emitter->particles_count; ++i)
- {
- particle_update(emitter, i, dt, v0, v1);
-
- if ((emitter->particles[i].life -= dt) <= 0.0f)
- particle_remove(emitter, i--);
- }
-
- // spawn particle
- emitter->spawn_time -= dt;
- emitter->spawn_last += dt;
-
- if (emitter->spawn_time > 0.0f && emitter->spawn_last >= (1.0f / emitter->spawn_rate))
- {
- particle_spawn(emitter);
- emitter->spawn_last = 0.0f; // -= dt;
- }
-
- qsort(emitter->particles, emitter->particles_count, sizeof(particle_t), particle_compare);
- }
-
- static void particle_emitter_render(particle_emitter_t *emitter, LPDIRECT3DDEVICE9 device)
- {
- ASSERT(emitter);
- ASSERT(device);
-
- static particle_vertex_t *vertices;
-
- renderer::vbuffer_lock(emitter->visual.vb, (void **)&vertices, 0, 0);
- for (uint32_t i = 0; i < emitter->particles_count; ++i)
- {
- memcpy(vertices + i * 4, emitter->particles[i].vertices,
- sizeof(particle_vertex_t) * 4);
- }
- renderer::vbuffer_unlock(emitter->visual.vb);
-
- device->SetStreamSource(0, emitter->visual.vb->buffer, 0, sizeof(particle_vertex_t));
- device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0,
- emitter->particles_count * 4, 0, emitter->particles_count * 2);
- }
-
- void particle_system_create(particle_system_t *psys)
- {
- ASSERT(psys);
-
- memset(psys, 0, sizeof(particle_system_t));
-
- static const uint32_t indices_count = PARTICLES_MAX * 6;
- static uint32_t indices[indices_count];
-
- for (uint32_t i = 0, j = 0; i < indices_count; i += 6, j += 4)
- {
- indices[i + 0] = j + 0;
- indices[i + 1] = j + 2;
- indices[i + 2] = j + 1;
- indices[i + 3] = j + 0;
- indices[i + 4] = j + 3;
- indices[i + 5] = j + 2;
- }
-
- psys->visual.ib = renderer::ibuffer_create(IB_32BIT, sizeof(indices), (const byte *)indices);
- ASSERT(psys->visual.ib);
-
- psys->visual.vlayout = renderer::get_vertex_layout(VE_POSITION | VE_COLOR | VE_TEXTURE0);
- D3DXMatrixIdentity(&psys->visual.transform);
-
- for (uint32_t i = 0; i < PARTICLE_EMITTERS_MAX; ++i)
- {
- psys->emitters[i].visual.vb = renderer::vbuffer_create(PARTICLES_MAX
- * sizeof(particle_vertex_t) * 4, NULL, D3DUSAGE_DYNAMIC);
- ASSERT(psys->emitters[i].visual.vb);
- }
-
- for (uint32_t i = 0; i < PARTICLE_EMITTERS_MAX; ++i)
- {
- for (uint32_t j = 0; j < PARTICLES_MAX; ++j)
- {
- particle_t *particle = psys->emitters[i].particles + j;
-
- particle->vertices[0].u = 0.0f;
- particle->vertices[0].v = 1.0f;
- particle->vertices[1].u = 0.0f;
- particle->vertices[1].v = 0.0f;
- particle->vertices[2].u = 1.0f;
- particle->vertices[2].v = 0.0f;
- particle->vertices[3].u = 1.0f;
- particle->vertices[3].v = 1.0f;
- }
- }
- }
-
- void particle_system_add(particle_system_t *psys, const particle_desc_t *desc)
- {
- ASSERT(psys);
-
- if (psys->emitters_count >= PARTICLE_EMITTERS_MAX)
- return;
-
- particle_emitter_t *emitter = psys->emitters + psys->emitters_count++;
-
- emitter->particles_count = 0;
- emitter->spawn_last = 0.0f;
-
- emitter->visual.texture = desc->texture;
- emitter->position = desc->position;
- emitter->direction = desc->direction;
- emitter->spawn_rate = desc->rate;
- emitter->spawn_time = desc->time;
- memcpy(emitter->speed, desc->speed, sizeof(emitter->speed));
- memcpy(emitter->life, desc->life, sizeof(emitter->life));
- memcpy(emitter->size, desc->size, sizeof(emitter->size));
- memcpy(emitter->color, desc->color, sizeof(emitter->color));
- }
-
- inline static void emitter_remove(particle_system_t *psys, uint32_t i)
- {
- uint32_t j = --psys->emitters_count;
-
- if (i != j)
- psys->emitters[i] = psys->emitters[j];
- //memcpy(psys->emitters + i, psys->emitters + j, sizeof(particle_emitter_t));
- }
-
- static int emitter_compare(const void *a, const void *b)
- {
- ASSERT(s_camera);
- ASSERT(a && b);
-
- const particle_emitter_t *e1 = (particle_emitter_t *)a,
- *e2 = (particle_emitter_t *)b;
-
- D3DXVECTOR3 d1 = e1->position - s_camera->position,
- d2 = e2->position - s_camera->position;
-
- return (int)(D3DXVec3LengthSq(&d2) - D3DXVec3LengthSq(&d1));
- }
-
- void particle_system_update(particle_system_t *psys, const camera_t &camera, float dt)
- {
- ASSERT(psys);
-
- s_camera = &camera;
-
- for (uint32_t i = 0; i < psys->emitters_count; ++i)
- {
- particle_emitter_update(psys->emitters + i, dt, camera);
-
- // remove emitter
- if (psys->emitters[i].particles_count == 0)
- emitter_remove(psys, i--);
- }
-
- qsort(psys->emitters, psys->emitters_count, sizeof(particle_emitter_t), emitter_compare);
- }
-
- void particle_system_render(particle_system_t *psys, const camera_t &camera, LPDIRECT3DDEVICE9 device)
- {
- ASSERT(psys);
- ASSERT(device);
-
- device->SetRenderState(D3DRS_LIGHTING, FALSE);
- device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-
- device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
- // D3DBLEND_INVSRCALPHA or D3DBLEND_ONE
- device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
-
- device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
- device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
- device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
-
- device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
- device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
-
- D3DXMATRIX world, inverted;
- D3DXVECTOR3 up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
-
- device->SetVertexDeclaration(psys->visual.vlayout->decl);
- device->SetIndices(psys->visual.ib->buffer);
-
- for (uint32_t i = 0; i < psys->emitters_count; ++i)
- {
- D3DXMatrixTranslation( &world, psys->emitters[i].position.x, psys->emitters[i].position.y, psys->emitters[i].position.z );
- device->SetTransform(D3DTS_WORLD, &world);
-
- device->SetTexture(0, psys->emitters[i].visual.texture->texture);
- particle_emitter_render(psys->emitters + i, device);
- }
-
- device->SetRenderState(D3DRS_LIGHTING, TRUE);
- device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
- }