PageRenderTime 106ms CodeModel.GetById 40ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

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