rev |
line source |
nuclear@0
|
1 #include <limits.h>
|
nuclear@0
|
2 #include "psyspp.h"
|
nuclear@0
|
3 #include "sdrman.h"
|
nuclear@0
|
4 #include "logger.h"
|
nuclear@0
|
5 #include "mesh.h" // just for the attrib enums
|
nuclear@0
|
6 #include "unistate.h"
|
nuclear@0
|
7 #include "datapath.h"
|
nuclear@0
|
8 #include "texman.h"
|
nuclear@0
|
9 #include "texgen.h"
|
nuclear@0
|
10
|
nuclear@15
|
11 using namespace goatgfx;
|
nuclear@15
|
12
|
nuclear@0
|
13 static void pdraw_start(const psys_emitter *em, void *cls);
|
nuclear@0
|
14 static void pdraw(const psys_emitter *em, const psys_particle *part, void *cls);
|
nuclear@0
|
15 static void pdraw_end(const psys_emitter *em, void *cls);
|
nuclear@0
|
16
|
nuclear@0
|
17 static unsigned int psys_load_texture(const char *fname, void *cls);
|
nuclear@0
|
18
|
nuclear@0
|
19 ParticleSystemAttributes::ParticleSystemAttributes()
|
nuclear@0
|
20 {
|
nuclear@0
|
21 tex = 0;
|
nuclear@0
|
22 own_psattr = true;
|
nuclear@0
|
23 psattr = new psys_attributes;
|
nuclear@0
|
24 psys_init_attr(psattr);
|
nuclear@0
|
25 }
|
nuclear@0
|
26
|
nuclear@0
|
27 ParticleSystemAttributes::ParticleSystemAttributes(psys_attributes *psattr)
|
nuclear@0
|
28 {
|
nuclear@0
|
29 tex = 0;
|
nuclear@0
|
30 own_psattr = false;
|
nuclear@0
|
31 this->psattr = psattr;
|
nuclear@0
|
32 }
|
nuclear@0
|
33
|
nuclear@0
|
34 ParticleSystemAttributes::~ParticleSystemAttributes()
|
nuclear@0
|
35 {
|
nuclear@0
|
36 if(own_psattr) {
|
nuclear@0
|
37 psys_destroy_attr(psattr);
|
nuclear@0
|
38 delete psattr;
|
nuclear@0
|
39 }
|
nuclear@0
|
40 }
|
nuclear@0
|
41
|
nuclear@0
|
42 ParticleSystemAttributes::ParticleSystemAttributes(const ParticleSystemAttributes &rhs)
|
nuclear@0
|
43 {
|
nuclear@0
|
44 own_psattr = true;
|
nuclear@0
|
45 tex = rhs.tex;
|
nuclear@0
|
46 psattr = new psys_attributes;
|
nuclear@0
|
47 psys_init_attr(psattr);
|
nuclear@0
|
48
|
nuclear@0
|
49 psys_copy_attr(psattr, rhs.psattr);
|
nuclear@0
|
50 }
|
nuclear@0
|
51
|
nuclear@0
|
52 ParticleSystemAttributes &ParticleSystemAttributes::operator =(const ParticleSystemAttributes &rhs)
|
nuclear@0
|
53 {
|
nuclear@0
|
54 if(&rhs != this) {
|
nuclear@0
|
55 tex = rhs.tex;
|
nuclear@0
|
56 psys_copy_attr(psattr, rhs.psattr);
|
nuclear@0
|
57 }
|
nuclear@0
|
58 return *this;
|
nuclear@0
|
59 }
|
nuclear@0
|
60
|
nuclear@0
|
61 bool ParticleSystemAttributes::load(const char *fname)
|
nuclear@0
|
62 {
|
nuclear@0
|
63 psys_texture_loader(psys_load_texture, 0, this);
|
nuclear@15
|
64 return psys_load_attr(psattr, goatgfx::datafile_path(fname).c_str()) != -1;
|
nuclear@0
|
65 }
|
nuclear@0
|
66
|
nuclear@0
|
67 bool ParticleSystemAttributes::load(FILE *fp)
|
nuclear@0
|
68 {
|
nuclear@0
|
69 psys_texture_loader(psys_load_texture, 0, this);
|
nuclear@0
|
70 return psys_load_attr_stream(psattr, fp) != -1;
|
nuclear@0
|
71 }
|
nuclear@0
|
72
|
nuclear@0
|
73 bool ParticleSystemAttributes::save(const char *fname) const
|
nuclear@0
|
74 {
|
nuclear@0
|
75 return psys_save_attr(psattr, fname) != -1;
|
nuclear@0
|
76 }
|
nuclear@0
|
77
|
nuclear@0
|
78 bool ParticleSystemAttributes::save(FILE *fp) const
|
nuclear@0
|
79 {
|
nuclear@0
|
80 return psys_save_attr_stream(psattr, fp) != -1;
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83 void ParticleSystemAttributes::set_part_color(const Vector3 &color, float t)
|
nuclear@0
|
84 {
|
nuclear@0
|
85 psys_set_value3(&psattr->part_attr.color, (anm_time_t)(t * 1000.0), v3_cons(color.x, color.y, color.z));
|
nuclear@0
|
86 }
|
nuclear@0
|
87
|
nuclear@0
|
88 void ParticleSystemAttributes::set_part_alpha(float alpha, float t)
|
nuclear@0
|
89 {
|
nuclear@0
|
90 psys_set_value(&psattr->part_attr.alpha, (anm_time_t)(t * 1000.0), alpha);
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 void ParticleSystemAttributes::set_part_scale(float size, float t)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 psys_set_value(&psattr->part_attr.size, (anm_time_t)(t * 1000.0), size);
|
nuclear@0
|
96 }
|
nuclear@0
|
97
|
nuclear@0
|
98
|
nuclear@0
|
99 // emmiter attributes
|
nuclear@0
|
100 void ParticleSystemAttributes::set_texture(Texture *tex)
|
nuclear@0
|
101 {
|
nuclear@0
|
102 this->tex = tex;
|
nuclear@0
|
103 psattr->tex = tex->get_id();
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@0
|
106 Texture *ParticleSystemAttributes::get_texture() const
|
nuclear@0
|
107 {
|
nuclear@0
|
108 return tex;
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 void ParticleSystemAttributes::set_spawn_range(const Vector3 &range, long tm)
|
nuclear@0
|
112 {
|
nuclear@0
|
113 psys_set_value3(&psattr->spawn_range, ANM_MSEC2TM(tm), v3_cons(range.x, range.y, range.z));
|
nuclear@0
|
114 }
|
nuclear@0
|
115
|
nuclear@0
|
116 void ParticleSystemAttributes::set_spawn_rate(float rate, long tm)
|
nuclear@0
|
117 {
|
nuclear@0
|
118 psys_set_value(&psattr->rate, ANM_MSEC2TM(tm), rate);
|
nuclear@0
|
119 }
|
nuclear@0
|
120
|
nuclear@0
|
121 float ParticleSystemAttributes::get_spawn_rate(long tm) const
|
nuclear@0
|
122 {
|
nuclear@0
|
123 return psys_get_value(&psattr->rate, ANM_MSEC2TM(tm));
|
nuclear@0
|
124 }
|
nuclear@0
|
125
|
nuclear@0
|
126 void ParticleSystemAttributes::set_life(float life, float range, long tm)
|
nuclear@0
|
127 {
|
nuclear@0
|
128 psys_set_anm_rnd(&psattr->life, ANM_MSEC2TM(tm), life, range);
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 void ParticleSystemAttributes::set_size(float sz, float range, long tm)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 psys_set_anm_rnd(&psattr->size, ANM_MSEC2TM(tm), sz, range);
|
nuclear@0
|
134 }
|
nuclear@0
|
135
|
nuclear@0
|
136 void ParticleSystemAttributes::set_spawn_dir(const Vector3 &dir, const Vector3 &range, long tm)
|
nuclear@0
|
137 {
|
nuclear@0
|
138 psys_set_anm_rnd3(&psattr->dir, ANM_MSEC2TM(tm), v3_cons(dir.x, dir.y, dir.z), v3_cons(range.x, range.y, range.z));
|
nuclear@0
|
139 }
|
nuclear@0
|
140
|
nuclear@0
|
141 void ParticleSystemAttributes::set_gravity(const Vector3 &grav, long tm)
|
nuclear@0
|
142 {
|
nuclear@0
|
143 psys_set_value3(&psattr->grav, ANM_MSEC2TM(tm), v3_cons(grav.x, grav.y, grav.z));
|
nuclear@0
|
144 }
|
nuclear@0
|
145
|
nuclear@0
|
146 void ParticleSystemAttributes::set_drag(float drag)
|
nuclear@0
|
147 {
|
nuclear@0
|
148 psattr->drag = drag;
|
nuclear@0
|
149 }
|
nuclear@0
|
150
|
nuclear@0
|
151 void ParticleSystemAttributes::set_particle_limit(int lim)
|
nuclear@0
|
152 {
|
nuclear@0
|
153 psattr->max_particles = lim;
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156
|
nuclear@0
|
157 // ---- ParticleSystem ----
|
nuclear@0
|
158
|
nuclear@0
|
159 ParticleSystem::ParticleSystem()
|
nuclear@0
|
160 : attr(&psys.attr)
|
nuclear@0
|
161 {
|
nuclear@0
|
162 psys_init(&psys);
|
nuclear@0
|
163 psys_draw_func(&psys, pdraw, pdraw_start, pdraw_end, (void*)this);
|
nuclear@0
|
164 start_time = LONG_MIN;
|
nuclear@0
|
165 last_upd_time = LONG_MIN;
|
nuclear@0
|
166 }
|
nuclear@0
|
167
|
nuclear@0
|
168 ParticleSystem::~ParticleSystem()
|
nuclear@0
|
169 {
|
nuclear@0
|
170 psys_destroy(&psys);
|
nuclear@0
|
171 }
|
nuclear@0
|
172
|
nuclear@0
|
173 void ParticleSystem::set_start_time(long tm)
|
nuclear@0
|
174 {
|
nuclear@0
|
175 start_time = tm;
|
nuclear@0
|
176 }
|
nuclear@0
|
177
|
nuclear@0
|
178 bool ParticleSystem::is_active() const
|
nuclear@0
|
179 {
|
nuclear@0
|
180 float rate = attr.get_spawn_rate(last_upd_time);
|
nuclear@0
|
181 return psys.pcount > 0 || last_upd_time == 0;// || rate > 0.0;
|
nuclear@0
|
182 }
|
nuclear@0
|
183
|
nuclear@0
|
184 ParticleSystemAttributes *ParticleSystem::get_attr()
|
nuclear@0
|
185 {
|
nuclear@0
|
186 return &attr;
|
nuclear@0
|
187 }
|
nuclear@0
|
188
|
nuclear@0
|
189 const ParticleSystemAttributes *ParticleSystem::get_attr() const
|
nuclear@0
|
190 {
|
nuclear@0
|
191 return &attr;
|
nuclear@0
|
192 }
|
nuclear@0
|
193
|
nuclear@0
|
194 void ParticleSystem::set_attr(const ParticleSystemAttributes &pattr)
|
nuclear@0
|
195 {
|
nuclear@0
|
196 attr = pattr;
|
nuclear@0
|
197 }
|
nuclear@0
|
198
|
nuclear@0
|
199 bool ParticleSystem::load(const char *fname)
|
nuclear@0
|
200 {
|
nuclear@0
|
201 psys_texture_loader(psys_load_texture, 0, &attr);
|
nuclear@0
|
202 return attr.load(fname);
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 bool ParticleSystem::save(const char *fname) const
|
nuclear@0
|
206 {
|
nuclear@0
|
207 return attr.save(fname);
|
nuclear@0
|
208 }
|
nuclear@0
|
209
|
nuclear@0
|
210 void ParticleSystem::update(long tm)
|
nuclear@0
|
211 {
|
nuclear@0
|
212 if(start_time > LONG_MIN) {
|
nuclear@0
|
213 tm -= start_time;
|
nuclear@0
|
214 }
|
nuclear@0
|
215
|
nuclear@0
|
216 Matrix4x4 xform;
|
nuclear@0
|
217 get_xform(tm, &xform);
|
nuclear@0
|
218
|
nuclear@0
|
219 Vector3 pos = Vector3(0, 0, 0).transformed(xform);
|
nuclear@0
|
220
|
nuclear@0
|
221 psys_set_pos(&psys, v3_cons(pos.x, pos.y, pos.z), 0);
|
nuclear@0
|
222 psys_update(&psys, (double)tm / 1000.0);
|
nuclear@0
|
223
|
nuclear@0
|
224 last_upd_time = tm;
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 void ParticleSystem::draw() const
|
nuclear@0
|
228 {
|
nuclear@0
|
229 psys_draw(&psys);
|
nuclear@0
|
230 }
|
nuclear@0
|
231
|
nuclear@0
|
232 // ---- particle drawing ----
|
nuclear@0
|
233 struct PVertex {
|
nuclear@0
|
234 Vector4 color;
|
nuclear@0
|
235 Vector3 pos;
|
nuclear@0
|
236 Vector2 texcoord;
|
nuclear@0
|
237 };
|
nuclear@0
|
238
|
nuclear@0
|
239
|
nuclear@0
|
240 #define USE_VBO
|
nuclear@0
|
241 #define USE_IBO
|
nuclear@0
|
242
|
nuclear@0
|
243
|
nuclear@0
|
244 #define MAX_DRAW_PART 256
|
nuclear@0
|
245 #define MAX_PVERTS (MAX_DRAW_PART * 4)
|
nuclear@0
|
246 static PVertex *pvarr, *pvptr;
|
nuclear@0
|
247
|
nuclear@0
|
248 // double-buffered vbo set, write on one, while drawing from the other
|
nuclear@0
|
249
|
nuclear@0
|
250 #ifdef USE_VBO
|
nuclear@0
|
251 static unsigned int vbo[2];
|
nuclear@0
|
252 static int cur_buf; // current write vbo
|
nuclear@0
|
253 #endif
|
nuclear@0
|
254 static int num_buffered; // number of particles bufferd, will flush when >= MAX_DRAW_PART
|
nuclear@0
|
255
|
nuclear@0
|
256 // ok so the index array is constant, regardless of the particle system
|
nuclear@0
|
257 // so this is a static index buffer created in init_particle_draw which should
|
nuclear@0
|
258 // be called once.
|
nuclear@0
|
259 #define MAX_PVIDX (MAX_DRAW_PART * 6)
|
nuclear@0
|
260 #ifdef USE_IBO
|
nuclear@0
|
261 static unsigned int ibo;
|
nuclear@0
|
262 #endif
|
nuclear@0
|
263 unsigned int *pvidx;
|
nuclear@0
|
264
|
nuclear@0
|
265 static ShaderProg *psdr; // particle shader
|
nuclear@24
|
266 static Texture *blank_tex;
|
nuclear@0
|
267
|
nuclear@0
|
268 static inline void init_particle_draw()
|
nuclear@0
|
269 {
|
nuclear@0
|
270 static bool done_init;
|
nuclear@0
|
271 if(done_init) {
|
nuclear@0
|
272 return; // once
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 pvidx = new unsigned int[MAX_PVIDX];
|
nuclear@0
|
276 unsigned int *ptr = pvidx;
|
nuclear@0
|
277
|
nuclear@0
|
278 static const unsigned int idxoffs[] = { 0, 1, 2, 0, 2, 3 };
|
nuclear@0
|
279
|
nuclear@0
|
280 for(int i=0; i<MAX_DRAW_PART; i++) {
|
nuclear@0
|
281 for(int j=0; j<6; j++) {
|
nuclear@0
|
282 *ptr++ = i * 4 + idxoffs[j];
|
nuclear@0
|
283 }
|
nuclear@0
|
284 }
|
nuclear@0
|
285
|
nuclear@0
|
286 #ifdef USE_IBO
|
nuclear@0
|
287 glGenBuffers(1, &ibo);
|
nuclear@0
|
288 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@0
|
289 glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_PVIDX * sizeof *pvidx, pvidx, GL_STATIC_DRAW);
|
nuclear@0
|
290 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
291
|
nuclear@0
|
292 delete [] pvidx;
|
nuclear@0
|
293 #endif
|
nuclear@0
|
294
|
nuclear@0
|
295 #ifdef USE_VBO
|
nuclear@0
|
296 // create the stream vertex buffers (double buffering)
|
nuclear@0
|
297 glGenBuffers(2, vbo);
|
nuclear@0
|
298 for(int i=0; i<2; i++) {
|
nuclear@0
|
299 glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
|
nuclear@0
|
300 glBufferData(GL_ARRAY_BUFFER, MAX_PVERTS * sizeof(PVertex), 0, GL_STREAM_DRAW);
|
nuclear@0
|
301 }
|
nuclear@0
|
302 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@0
|
303 #else
|
nuclear@0
|
304 pvarr = new PVertex[MAX_PVERTS];
|
nuclear@0
|
305 pvptr = pvarr;
|
nuclear@0
|
306 #endif
|
nuclear@0
|
307
|
nuclear@0
|
308 // load shader program
|
nuclear@0
|
309 if(!(psdr = get_sdrprog("psdr.v.glsl", "psdr.p.glsl"))) {
|
nuclear@0
|
310 error_log("failed to load particle shader!\n");
|
nuclear@0
|
311 }
|
nuclear@0
|
312
|
nuclear@0
|
313 // create empty texture
|
nuclear@0
|
314 Image *img = texgen_solid(8, 8, Vector4(1, 1, 1, 1));
|
nuclear@24
|
315 blank_tex = new Texture;
|
nuclear@0
|
316 blank_tex->set_image(*img);
|
nuclear@0
|
317 delete img;
|
nuclear@0
|
318
|
nuclear@0
|
319 done_init = true;
|
nuclear@0
|
320 }
|
nuclear@0
|
321
|
nuclear@0
|
322 static void pdraw_flush()
|
nuclear@0
|
323 {
|
nuclear@0
|
324 #ifdef USE_VBO
|
nuclear@0
|
325 // assuming vbo[cur_buf] is bound
|
nuclear@0
|
326 glUnmapBuffer(GL_ARRAY_BUFFER);
|
nuclear@0
|
327 #endif
|
nuclear@0
|
328
|
nuclear@0
|
329 // draw from the bound buffer 6 indices per particle
|
nuclear@0
|
330 #ifdef USE_IBO
|
nuclear@0
|
331 glDrawElements(GL_TRIANGLES, num_buffered * 6, GL_UNSIGNED_INT, 0);
|
nuclear@0
|
332 #else
|
nuclear@0
|
333 glDrawElements(GL_TRIANGLES, num_buffered * 6, GL_UNSIGNED_INT, pvidx);
|
nuclear@0
|
334 #endif
|
nuclear@0
|
335 num_buffered = 0;
|
nuclear@0
|
336
|
nuclear@0
|
337 #ifdef USE_VBO
|
nuclear@0
|
338 // map the next buffer (write buffer) while the previous is drawing
|
nuclear@0
|
339 cur_buf = (cur_buf + 1) & 1;
|
nuclear@0
|
340 glBindBuffer(GL_ARRAY_BUFFER, vbo[cur_buf]);
|
nuclear@0
|
341 pvarr = (PVertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
nuclear@0
|
342 #endif
|
nuclear@0
|
343 pvptr = pvarr;
|
nuclear@0
|
344 }
|
nuclear@0
|
345
|
nuclear@0
|
346 static void pdraw_start(const psys_emitter *em, void *cls)
|
nuclear@0
|
347 {
|
nuclear@0
|
348 ParticleSystem *ps = (ParticleSystem*)cls;
|
nuclear@0
|
349
|
nuclear@0
|
350 init_particle_draw();
|
nuclear@0
|
351
|
nuclear@0
|
352 num_buffered = 0;
|
nuclear@0
|
353
|
nuclear@0
|
354 #ifdef USE_IBO
|
nuclear@0
|
355 // bind the particle index buffer which is static
|
nuclear@0
|
356 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@0
|
357 #endif
|
nuclear@0
|
358
|
nuclear@0
|
359 #ifdef USE_VBO
|
nuclear@0
|
360 // map the current write buffer
|
nuclear@0
|
361 glBindBuffer(GL_ARRAY_BUFFER, vbo[cur_buf]);
|
nuclear@0
|
362 pvarr = (PVertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
nuclear@0
|
363 #endif
|
nuclear@0
|
364 pvptr = pvarr;
|
nuclear@0
|
365
|
nuclear@0
|
366 Texture *tex = ps->get_attr()->get_texture();
|
nuclear@0
|
367 if(tex) {
|
nuclear@0
|
368 tex->bind();
|
nuclear@0
|
369 } else {
|
nuclear@0
|
370 blank_tex->bind();
|
nuclear@0
|
371 }
|
nuclear@0
|
372 psdr->bind();
|
nuclear@0
|
373
|
nuclear@0
|
374 glDisable(GL_DEPTH_TEST);
|
nuclear@0
|
375 glDisable(GL_CULL_FACE);
|
nuclear@0
|
376 glEnable(GL_BLEND);
|
nuclear@0
|
377 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
nuclear@0
|
378 glDepthMask(0);
|
nuclear@0
|
379
|
nuclear@0
|
380 glEnableVertexAttribArray(MESH_ATTR_VERTEX);
|
nuclear@0
|
381 glEnableVertexAttribArray(MESH_ATTR_COLOR);
|
nuclear@0
|
382 glEnableVertexAttribArray(MESH_ATTR_TEXCOORD);
|
nuclear@0
|
383
|
nuclear@0
|
384 #ifdef USE_VBO
|
nuclear@0
|
385 glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)((char*)&pvarr->pos - (char*)pvarr));
|
nuclear@0
|
386 glVertexAttribPointer(MESH_ATTR_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof *pvarr, (void*)((char*)&pvarr->color - (char*)pvarr));
|
nuclear@0
|
387 glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)((char*)&pvarr->texcoord - (char*)pvarr));
|
nuclear@0
|
388 #else
|
nuclear@0
|
389 glVertexAttribPointer(MESH_ATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)&pvarr->pos);
|
nuclear@0
|
390 glVertexAttribPointer(MESH_ATTR_COLOR, 4, GL_FLOAT, GL_TRUE, sizeof *pvarr, (void*)&pvarr->color);
|
nuclear@0
|
391 glVertexAttribPointer(MESH_ATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof *pvarr, (void*)&pvarr->texcoord);
|
nuclear@0
|
392 #endif
|
nuclear@0
|
393 }
|
nuclear@0
|
394
|
nuclear@0
|
395 static void pdraw(const psys_emitter *em, const psys_particle *part, void *cls)
|
nuclear@0
|
396 {
|
nuclear@0
|
397 ParticleSystem *ps = (ParticleSystem*)cls;
|
nuclear@0
|
398
|
nuclear@0
|
399 static const Vector3 pv[] = {
|
nuclear@0
|
400 Vector3(-0.5, -0.5, 0),
|
nuclear@0
|
401 Vector3(0.5, -0.5, 0),
|
nuclear@0
|
402 Vector3(0.5, 0.5, 0),
|
nuclear@0
|
403 Vector3(-0.5, 0.5, 0)
|
nuclear@0
|
404 };
|
nuclear@0
|
405 static const Vector2 tex[] = {
|
nuclear@0
|
406 Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)
|
nuclear@0
|
407 };
|
nuclear@0
|
408 Vector4 color = Vector4(part->color.x, part->color.y, part->color.z, part->alpha);
|
nuclear@0
|
409
|
nuclear@0
|
410 for(int i=0; i<4; i++) {
|
nuclear@0
|
411 pvptr->color = color;
|
nuclear@0
|
412 pvptr->pos = pv[i] * part->size + part->pos;
|
nuclear@0
|
413 pvptr->texcoord = tex[i];
|
nuclear@0
|
414 pvptr++;
|
nuclear@0
|
415 }
|
nuclear@0
|
416 // XXX we don't need billboarding for this game, so don't bother
|
nuclear@0
|
417
|
nuclear@0
|
418 // if we reached the maximum number of buffered particles, draw them
|
nuclear@0
|
419 if(++num_buffered >= MAX_DRAW_PART) {
|
nuclear@0
|
420 pdraw_flush(); // this will reset the counter
|
nuclear@0
|
421 }
|
nuclear@0
|
422 }
|
nuclear@0
|
423
|
nuclear@0
|
424 static void pdraw_end(const psys_emitter *em, void *cls)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 // if we have leftover particles buffered, draw them before returning
|
nuclear@0
|
427 if(num_buffered) {
|
nuclear@0
|
428 pdraw_flush();
|
nuclear@0
|
429 }
|
nuclear@0
|
430
|
nuclear@0
|
431 // cleanup
|
nuclear@0
|
432 glDisableVertexAttribArray(MESH_ATTR_VERTEX);
|
nuclear@0
|
433 glDisableVertexAttribArray(MESH_ATTR_COLOR);
|
nuclear@0
|
434 glDisableVertexAttribArray(MESH_ATTR_TEXCOORD);
|
nuclear@0
|
435
|
nuclear@0
|
436 #ifdef USE_VBO
|
nuclear@0
|
437 glUnmapBuffer(GL_ARRAY_BUFFER);
|
nuclear@0
|
438 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@0
|
439 #endif
|
nuclear@0
|
440 #ifdef USE_IBO
|
nuclear@0
|
441 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
442 #endif
|
nuclear@0
|
443
|
nuclear@0
|
444 glDepthMask(1);
|
nuclear@0
|
445 glDisable(GL_BLEND);
|
nuclear@0
|
446
|
nuclear@0
|
447 glEnable(GL_DEPTH_TEST);
|
nuclear@0
|
448 glEnable(GL_CULL_FACE);
|
nuclear@0
|
449 }
|
nuclear@0
|
450
|
nuclear@0
|
451 static unsigned int psys_load_texture(const char *fname, void *cls)
|
nuclear@0
|
452 {
|
nuclear@0
|
453 ParticleSystemAttributes *attr = (ParticleSystemAttributes*)cls;
|
nuclear@0
|
454
|
nuclear@0
|
455 Texture *tex = texset.get(fname);
|
nuclear@0
|
456 if(tex) {
|
nuclear@0
|
457 attr->set_texture(tex);
|
nuclear@0
|
458 return tex->get_id();
|
nuclear@0
|
459 }
|
nuclear@0
|
460 return 0;
|
nuclear@0
|
461 }
|