rev |
line source |
nuclear@0
|
1 #include <stdlib.h>
|
nuclear@0
|
2 #include <math.h>
|
nuclear@0
|
3 #include <assert.h>
|
nuclear@0
|
4 #include <pthread.h>
|
nuclear@0
|
5 #include <vmath.h>
|
nuclear@0
|
6 #include "psys_impl.h"
|
nuclear@0
|
7
|
nuclear@0
|
8 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls);
|
nuclear@0
|
9 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls);
|
nuclear@0
|
10
|
nuclear@0
|
11 static int init_v3track(struct v3track *v3t);
|
nuclear@0
|
12 static void destroy_v3track(struct v3track *v3t);
|
nuclear@0
|
13 static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v);
|
nuclear@0
|
14 static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm);
|
nuclear@0
|
15
|
nuclear@0
|
16 /* particle pool */
|
nuclear@0
|
17 static struct psys_particle *ppool;
|
nuclear@0
|
18 static int ppool_size;
|
nuclear@0
|
19 static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER;
|
nuclear@0
|
20
|
nuclear@0
|
21 static struct psys_particle *palloc(void);
|
nuclear@0
|
22 static void pfree(struct psys_particle *p);
|
nuclear@0
|
23
|
nuclear@0
|
24 /* --- constructors and shit --- */
|
nuclear@0
|
25
|
nuclear@0
|
26 struct psys_emitter *psys_create(void)
|
nuclear@0
|
27 {
|
nuclear@0
|
28 struct psys_emitter *em;
|
nuclear@0
|
29
|
nuclear@0
|
30 if(!(em = malloc(sizeof *em))) {
|
nuclear@0
|
31 return 0;
|
nuclear@0
|
32 }
|
nuclear@0
|
33 if(psys_init(em) == -1) {
|
nuclear@0
|
34 free(em);
|
nuclear@0
|
35 return 0;
|
nuclear@0
|
36 }
|
nuclear@0
|
37 return em;
|
nuclear@0
|
38 }
|
nuclear@0
|
39
|
nuclear@0
|
40 void psys_free(struct psys_emitter *em)
|
nuclear@0
|
41 {
|
nuclear@0
|
42 psys_destroy(em);
|
nuclear@0
|
43 free(em);
|
nuclear@0
|
44 }
|
nuclear@0
|
45
|
nuclear@0
|
46 int psys_init(struct psys_emitter *em)
|
nuclear@0
|
47 {
|
nuclear@0
|
48 memset(em, 0, sizeof *em);
|
nuclear@0
|
49
|
nuclear@0
|
50 if(anm_init_node(&em->prs) == -1) {
|
nuclear@1
|
51 psys_destroy(em);
|
nuclear@0
|
52 return -1;
|
nuclear@0
|
53 }
|
nuclear@0
|
54 if(anm_init_track(&em->rate) == -1) {
|
nuclear@1
|
55 psys_destroy(em);
|
nuclear@1
|
56 return -1;
|
nuclear@1
|
57 }
|
nuclear@1
|
58 if(anm_init_track(&em->life) == -1) {
|
nuclear@1
|
59 psys_destroy(em);
|
nuclear@0
|
60 return -1;
|
nuclear@0
|
61 }
|
nuclear@0
|
62 if(init_v3track(&em->dir) == -1) {
|
nuclear@1
|
63 psys_destroy(em);
|
nuclear@1
|
64 return -1;
|
nuclear@1
|
65 }
|
nuclear@1
|
66 if(init_v3track(&em->grav) == -1) {
|
nuclear@1
|
67 psys_destroy(em);
|
nuclear@0
|
68 return -1;
|
nuclear@0
|
69 }
|
nuclear@0
|
70
|
nuclear@0
|
71 em->spawn = spawn;
|
nuclear@0
|
72 em->update = update_particle;
|
nuclear@0
|
73
|
nuclear@0
|
74 em->draw = psys_gl_draw;
|
nuclear@0
|
75 em->draw_start = psys_gl_draw_start;
|
nuclear@0
|
76 em->draw_end = psys_gl_draw_end;
|
nuclear@0
|
77
|
nuclear@0
|
78 return 0;
|
nuclear@0
|
79 }
|
nuclear@0
|
80
|
nuclear@0
|
81 void psys_destroy(struct psys_emitter *em)
|
nuclear@0
|
82 {
|
nuclear@0
|
83 struct psys_particle *part;
|
nuclear@0
|
84
|
nuclear@0
|
85 part = em->plist;
|
nuclear@0
|
86 while(part) {
|
nuclear@0
|
87 struct psys_particle *tmp = part;
|
nuclear@0
|
88 part = part->next;
|
nuclear@0
|
89 pfree(tmp);
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 anm_destroy_node(&em->prs);
|
nuclear@0
|
93 anm_destroy_track(&em->rate);
|
nuclear@0
|
94 destroy_v3track(&em->dir);
|
nuclear@0
|
95 }
|
nuclear@0
|
96
|
nuclear@2
|
97 void psys_set_texture(struct psys_emitter *em, unsigned int tex)
|
nuclear@2
|
98 {
|
nuclear@2
|
99 em->tex = tex;
|
nuclear@2
|
100 }
|
nuclear@2
|
101
|
nuclear@0
|
102 void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 anm_set_position(&em->prs, pos, ANM_SEC2TM(tm));
|
nuclear@0
|
105 }
|
nuclear@0
|
106
|
nuclear@0
|
107 void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm)
|
nuclear@0
|
108 {
|
nuclear@0
|
109 anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm));
|
nuclear@0
|
110 }
|
nuclear@0
|
111
|
nuclear@0
|
112 void psys_set_pivot(struct psys_emitter *em, vec3_t pivot)
|
nuclear@0
|
113 {
|
nuclear@0
|
114 anm_set_pivot(&em->prs, pivot);
|
nuclear@0
|
115 }
|
nuclear@0
|
116
|
nuclear@0
|
117 void psys_set_rate(struct psys_emitter *em, float rate, float tm)
|
nuclear@0
|
118 {
|
nuclear@0
|
119 anm_set_value(&em->rate, ANM_SEC2TM(tm), rate);
|
nuclear@0
|
120 }
|
nuclear@0
|
121
|
nuclear@1
|
122 void psys_set_life(struct psys_emitter *em, float life, float tm)
|
nuclear@1
|
123 {
|
nuclear@1
|
124 anm_set_value(&em->life, ANM_SEC2TM(tm), life);
|
nuclear@1
|
125 }
|
nuclear@1
|
126
|
nuclear@0
|
127 void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm)
|
nuclear@0
|
128 {
|
nuclear@0
|
129 set_v3value(&em->dir, ANM_SEC2TM(tm), dir);
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@1
|
132 void psys_set_grav(struct psys_emitter *em, vec3_t grav, float tm)
|
nuclear@1
|
133 {
|
nuclear@1
|
134 set_v3value(&em->grav, ANM_SEC2TM(tm), grav);
|
nuclear@1
|
135 }
|
nuclear@1
|
136
|
nuclear@0
|
137
|
nuclear@0
|
138 void psys_clear_collision_planes(struct psys_emitter *em)
|
nuclear@0
|
139 {
|
nuclear@0
|
140 struct col_plane *plane;
|
nuclear@0
|
141
|
nuclear@0
|
142 plane = em->planes;
|
nuclear@0
|
143 while(plane) {
|
nuclear@0
|
144 struct col_plane *tmp = plane;
|
nuclear@0
|
145 plane = plane->next;
|
nuclear@1
|
146 free(tmp);
|
nuclear@0
|
147 }
|
nuclear@0
|
148 }
|
nuclear@0
|
149
|
nuclear@0
|
150 int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast)
|
nuclear@0
|
151 {
|
nuclear@0
|
152 struct col_plane *node;
|
nuclear@0
|
153
|
nuclear@0
|
154 if(!(node = malloc(sizeof *node))) {
|
nuclear@0
|
155 return -1;
|
nuclear@0
|
156 }
|
nuclear@0
|
157 node->p = plane;
|
nuclear@0
|
158 node->elasticity = elast;
|
nuclear@0
|
159 node->next = em->planes;
|
nuclear@0
|
160 em->planes = node;
|
nuclear@0
|
161 return 0;
|
nuclear@0
|
162 }
|
nuclear@0
|
163
|
nuclear@0
|
164 void psys_add_particle(struct psys_emitter *em, struct psys_particle *p)
|
nuclear@0
|
165 {
|
nuclear@0
|
166 p->next = em->plist;
|
nuclear@0
|
167 em->plist = p;
|
nuclear@0
|
168 }
|
nuclear@0
|
169
|
nuclear@0
|
170 void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls)
|
nuclear@0
|
171 {
|
nuclear@0
|
172 em->spawn = func;
|
nuclear@0
|
173 em->spawn_cls = cls;
|
nuclear@0
|
174 }
|
nuclear@0
|
175
|
nuclear@0
|
176 void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls)
|
nuclear@0
|
177 {
|
nuclear@0
|
178 em->update = func;
|
nuclear@0
|
179 em->upd_cls = cls;
|
nuclear@0
|
180 }
|
nuclear@0
|
181
|
nuclear@0
|
182 void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw,
|
nuclear@0
|
183 psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls)
|
nuclear@0
|
184 {
|
nuclear@0
|
185 em->draw = draw;
|
nuclear@0
|
186 em->draw_start = start;
|
nuclear@0
|
187 em->draw_end = end;
|
nuclear@0
|
188 em->draw_cls = cls;
|
nuclear@0
|
189 }
|
nuclear@0
|
190
|
nuclear@0
|
191 /* --- query current state --- */
|
nuclear@2
|
192 unsigned int psys_get_texture(struct psys_emitter *em)
|
nuclear@2
|
193 {
|
nuclear@2
|
194 return em->tex;
|
nuclear@2
|
195 }
|
nuclear@2
|
196
|
nuclear@0
|
197 vec3_t psys_get_pos(struct psys_emitter *em)
|
nuclear@0
|
198 {
|
nuclear@0
|
199 return em->cur_pos;
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 quat_t psys_get_rot(struct psys_emitter *em)
|
nuclear@0
|
203 {
|
nuclear@0
|
204 return em->cur_rot;
|
nuclear@0
|
205 }
|
nuclear@0
|
206
|
nuclear@0
|
207 float psys_get_rate(struct psys_emitter *em)
|
nuclear@0
|
208 {
|
nuclear@0
|
209 return em->cur_rate;
|
nuclear@0
|
210 }
|
nuclear@0
|
211
|
nuclear@0
|
212 float psys_get_life(struct psys_emitter *em)
|
nuclear@0
|
213 {
|
nuclear@0
|
214 return em->cur_life;
|
nuclear@0
|
215 }
|
nuclear@0
|
216
|
nuclear@0
|
217 vec3_t psys_get_dir(struct psys_emitter *em)
|
nuclear@0
|
218 {
|
nuclear@0
|
219 return em->cur_dir;
|
nuclear@0
|
220 }
|
nuclear@0
|
221
|
nuclear@1
|
222 vec3_t psys_get_grav(struct psys_emitter *em)
|
nuclear@1
|
223 {
|
nuclear@1
|
224 return em->cur_grav;
|
nuclear@1
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 /* --- update and render --- */
|
nuclear@0
|
228
|
nuclear@0
|
229 void psys_update(struct psys_emitter *em, float tm)
|
nuclear@0
|
230 {
|
nuclear@2
|
231 float dt, spawn_dt, spawn_tm;
|
nuclear@0
|
232 int i, spawn_count;
|
nuclear@0
|
233 struct psys_particle *p, pdummy;
|
nuclear@0
|
234 anm_time_t atm;
|
nuclear@0
|
235
|
nuclear@0
|
236 assert(em->spawn && em->update);
|
nuclear@0
|
237
|
nuclear@0
|
238 atm = ANM_SEC2TM(tm);
|
nuclear@0
|
239
|
nuclear@1
|
240 em->cur_rate = anm_get_value(&em->rate, atm);
|
nuclear@0
|
241 dt = tm - em->last_update;
|
nuclear@0
|
242
|
nuclear@0
|
243 /* how many particles to spawn for this interval ? */
|
nuclear@2
|
244 em->spawn_acc += em->cur_rate * dt;
|
nuclear@2
|
245 if(em->spawn_acc >= 1.0) {
|
nuclear@2
|
246 spawn_count = em->spawn_acc;
|
nuclear@2
|
247 em->spawn_acc = fmod(em->spawn_acc, 1.0);
|
nuclear@2
|
248 } else {
|
nuclear@2
|
249 spawn_count = 0;
|
nuclear@2
|
250 }
|
nuclear@0
|
251
|
nuclear@0
|
252 em->cur_dir = get_v3value(&em->dir, atm);
|
nuclear@0
|
253 em->cur_life = anm_get_value(&em->life, atm);
|
nuclear@1
|
254 em->cur_grav = get_v3value(&em->grav, atm);
|
nuclear@0
|
255
|
nuclear@0
|
256 spawn_dt = dt / (float)spawn_count;
|
nuclear@2
|
257 spawn_tm = em->last_update;
|
nuclear@0
|
258 for(i=0; i<spawn_count; i++) {
|
nuclear@0
|
259 /* update emitter position for this spawning */
|
nuclear@2
|
260 em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(spawn_tm));
|
nuclear@0
|
261
|
nuclear@0
|
262 if(!(p = palloc())) {
|
nuclear@0
|
263 return;
|
nuclear@0
|
264 }
|
nuclear@0
|
265 if(em->spawn(em, p, em->spawn_cls) == -1) {
|
nuclear@0
|
266 pfree(p);
|
nuclear@0
|
267 }
|
nuclear@2
|
268 spawn_tm += spawn_dt;
|
nuclear@0
|
269 }
|
nuclear@0
|
270
|
nuclear@0
|
271 /* update all particles */
|
nuclear@0
|
272 p = em->plist;
|
nuclear@0
|
273 while(p) {
|
nuclear@1
|
274 em->update(em, p, tm, dt, em->upd_cls);
|
nuclear@0
|
275 p = p->next;
|
nuclear@0
|
276 }
|
nuclear@0
|
277
|
nuclear@0
|
278 /* cleanup dead particles */
|
nuclear@0
|
279 pdummy.next = em->plist;
|
nuclear@0
|
280 p = &pdummy;
|
nuclear@0
|
281 while(p->next) {
|
nuclear@0
|
282 if(p->next->life <= 0) {
|
nuclear@0
|
283 struct psys_particle *tmp = p->next;
|
nuclear@0
|
284 p->next = p->next->next;
|
nuclear@0
|
285 pfree(tmp);
|
nuclear@0
|
286 } else {
|
nuclear@0
|
287 p = p->next;
|
nuclear@0
|
288 }
|
nuclear@0
|
289 }
|
nuclear@0
|
290 em->plist = pdummy.next;
|
nuclear@2
|
291
|
nuclear@2
|
292 em->last_update = tm;
|
nuclear@0
|
293 }
|
nuclear@0
|
294
|
nuclear@0
|
295 void psys_draw(struct psys_emitter *em)
|
nuclear@0
|
296 {
|
nuclear@0
|
297 struct psys_particle *p;
|
nuclear@0
|
298
|
nuclear@0
|
299 if(em->draw_start) {
|
nuclear@1
|
300 em->draw_start(em, em->draw_cls);
|
nuclear@0
|
301 }
|
nuclear@0
|
302
|
nuclear@0
|
303 p = em->plist;
|
nuclear@0
|
304 while(p) {
|
nuclear@1
|
305 em->draw(em, p, em->draw_cls);
|
nuclear@0
|
306 p = p->next;
|
nuclear@0
|
307 }
|
nuclear@0
|
308
|
nuclear@0
|
309 if(em->draw_end) {
|
nuclear@1
|
310 em->draw_end(em, em->draw_cls);
|
nuclear@0
|
311 }
|
nuclear@0
|
312 }
|
nuclear@0
|
313
|
nuclear@0
|
314 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls)
|
nuclear@0
|
315 {
|
nuclear@0
|
316 p->pos = em->cur_pos;
|
nuclear@0
|
317 p->vel = em->cur_dir;
|
nuclear@0
|
318 p->size = 1.0;
|
nuclear@0
|
319 p->life = em->cur_life;
|
nuclear@0
|
320
|
nuclear@0
|
321 psys_add_particle(em, p);
|
nuclear@0
|
322 return 0;
|
nuclear@0
|
323 }
|
nuclear@0
|
324
|
nuclear@0
|
325 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls)
|
nuclear@0
|
326 {
|
nuclear@1
|
327 vec3_t accel;
|
nuclear@0
|
328
|
nuclear@1
|
329 accel.x = em->cur_grav.x - p->vel.x * em->drag;
|
nuclear@1
|
330 accel.y = em->cur_grav.y - p->vel.y * em->drag;
|
nuclear@1
|
331 accel.z = em->cur_grav.z - p->vel.z * em->drag;
|
nuclear@1
|
332
|
nuclear@1
|
333 p->vel.x += accel.x * dt;
|
nuclear@1
|
334 p->vel.y += accel.y * dt;
|
nuclear@1
|
335 p->vel.z += accel.z * dt;
|
nuclear@0
|
336
|
nuclear@0
|
337 p->pos.x += p->vel.x * dt;
|
nuclear@0
|
338 p->pos.y += p->vel.y * dt;
|
nuclear@0
|
339 p->pos.z += p->vel.z * dt;
|
nuclear@2
|
340
|
nuclear@2
|
341 p->life -= dt;
|
nuclear@0
|
342 }
|
nuclear@0
|
343
|
nuclear@0
|
344 /* --- v3track helper --- */
|
nuclear@0
|
345
|
nuclear@0
|
346 int init_v3track(struct v3track *v3t)
|
nuclear@0
|
347 {
|
nuclear@0
|
348 if(anm_init_track(&v3t->x) == -1) {
|
nuclear@0
|
349 return -1;
|
nuclear@0
|
350 }
|
nuclear@0
|
351 if(anm_init_track(&v3t->y) == -1) {
|
nuclear@0
|
352 anm_destroy_track(&v3t->x);
|
nuclear@0
|
353 return -1;
|
nuclear@0
|
354 }
|
nuclear@0
|
355 if(anm_init_track(&v3t->z) == -1) {
|
nuclear@0
|
356 anm_destroy_track(&v3t->x);
|
nuclear@0
|
357 anm_destroy_track(&v3t->y);
|
nuclear@0
|
358 return -1;
|
nuclear@0
|
359 }
|
nuclear@0
|
360 return 0;
|
nuclear@0
|
361 }
|
nuclear@0
|
362
|
nuclear@0
|
363 static void destroy_v3track(struct v3track *v3t)
|
nuclear@0
|
364 {
|
nuclear@0
|
365 anm_destroy_track(&v3t->x);
|
nuclear@0
|
366 anm_destroy_track(&v3t->y);
|
nuclear@0
|
367 anm_destroy_track(&v3t->z);
|
nuclear@0
|
368 }
|
nuclear@0
|
369
|
nuclear@0
|
370 static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v)
|
nuclear@0
|
371 {
|
nuclear@0
|
372 anm_set_value(&v3t->x, tm, v.x);
|
nuclear@0
|
373 anm_set_value(&v3t->y, tm, v.y);
|
nuclear@0
|
374 anm_set_value(&v3t->z, tm, v.z);
|
nuclear@0
|
375 }
|
nuclear@0
|
376
|
nuclear@0
|
377 static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm)
|
nuclear@0
|
378 {
|
nuclear@0
|
379 vec3_t v;
|
nuclear@0
|
380 v.x = anm_get_value(&v3t->x, tm);
|
nuclear@0
|
381 v.y = anm_get_value(&v3t->y, tm);
|
nuclear@0
|
382 v.z = anm_get_value(&v3t->z, tm);
|
nuclear@0
|
383 return v;
|
nuclear@0
|
384 }
|
nuclear@0
|
385
|
nuclear@0
|
386 /* --- particle allocation pool --- */
|
nuclear@0
|
387
|
nuclear@0
|
388 static struct psys_particle *palloc(void)
|
nuclear@0
|
389 {
|
nuclear@0
|
390 struct psys_particle *p;
|
nuclear@0
|
391
|
nuclear@0
|
392 pthread_mutex_lock(&pool_lock);
|
nuclear@0
|
393 if(ppool) {
|
nuclear@0
|
394 p = ppool;
|
nuclear@0
|
395 ppool = ppool->next;
|
nuclear@0
|
396 ppool_size--;
|
nuclear@0
|
397 } else {
|
nuclear@0
|
398 p = malloc(sizeof *p);
|
nuclear@0
|
399 }
|
nuclear@0
|
400 pthread_mutex_unlock(&pool_lock);
|
nuclear@0
|
401
|
nuclear@0
|
402 if(p) {
|
nuclear@0
|
403 memset(p, 0, sizeof *p);
|
nuclear@1
|
404 /*reset_pattr(&p->attr);*/
|
nuclear@0
|
405 }
|
nuclear@0
|
406 return p;
|
nuclear@0
|
407 }
|
nuclear@0
|
408
|
nuclear@0
|
409 static void pfree(struct psys_particle *p)
|
nuclear@0
|
410 {
|
nuclear@0
|
411 pthread_mutex_lock(&pool_lock);
|
nuclear@0
|
412 p->next = ppool;
|
nuclear@0
|
413 ppool = p;
|
nuclear@0
|
414 ppool_size++;
|
nuclear@0
|
415 pthread_mutex_unlock(&pool_lock);
|
nuclear@0
|
416 }
|