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@0
|
97 void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm)
|
nuclear@0
|
98 {
|
nuclear@0
|
99 anm_set_position(&em->prs, pos, ANM_SEC2TM(tm));
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm)
|
nuclear@0
|
103 {
|
nuclear@0
|
104 anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm));
|
nuclear@0
|
105 }
|
nuclear@0
|
106
|
nuclear@0
|
107 void psys_set_pivot(struct psys_emitter *em, vec3_t pivot)
|
nuclear@0
|
108 {
|
nuclear@0
|
109 anm_set_pivot(&em->prs, pivot);
|
nuclear@0
|
110 }
|
nuclear@0
|
111
|
nuclear@0
|
112 void psys_set_rate(struct psys_emitter *em, float rate, float tm)
|
nuclear@0
|
113 {
|
nuclear@0
|
114 anm_set_value(&em->rate, ANM_SEC2TM(tm), rate);
|
nuclear@0
|
115 }
|
nuclear@0
|
116
|
nuclear@1
|
117 void psys_set_life(struct psys_emitter *em, float life, float tm)
|
nuclear@1
|
118 {
|
nuclear@1
|
119 anm_set_value(&em->life, ANM_SEC2TM(tm), life);
|
nuclear@1
|
120 }
|
nuclear@1
|
121
|
nuclear@0
|
122 void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm)
|
nuclear@0
|
123 {
|
nuclear@0
|
124 set_v3value(&em->dir, ANM_SEC2TM(tm), dir);
|
nuclear@0
|
125 }
|
nuclear@0
|
126
|
nuclear@1
|
127 void psys_set_grav(struct psys_emitter *em, vec3_t grav, float tm)
|
nuclear@1
|
128 {
|
nuclear@1
|
129 set_v3value(&em->grav, ANM_SEC2TM(tm), grav);
|
nuclear@1
|
130 }
|
nuclear@1
|
131
|
nuclear@0
|
132
|
nuclear@0
|
133 void psys_clear_collision_planes(struct psys_emitter *em)
|
nuclear@0
|
134 {
|
nuclear@0
|
135 struct col_plane *plane;
|
nuclear@0
|
136
|
nuclear@0
|
137 plane = em->planes;
|
nuclear@0
|
138 while(plane) {
|
nuclear@0
|
139 struct col_plane *tmp = plane;
|
nuclear@0
|
140 plane = plane->next;
|
nuclear@1
|
141 free(tmp);
|
nuclear@0
|
142 }
|
nuclear@0
|
143 }
|
nuclear@0
|
144
|
nuclear@0
|
145 int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast)
|
nuclear@0
|
146 {
|
nuclear@0
|
147 struct col_plane *node;
|
nuclear@0
|
148
|
nuclear@0
|
149 if(!(node = malloc(sizeof *node))) {
|
nuclear@0
|
150 return -1;
|
nuclear@0
|
151 }
|
nuclear@0
|
152 node->p = plane;
|
nuclear@0
|
153 node->elasticity = elast;
|
nuclear@0
|
154 node->next = em->planes;
|
nuclear@0
|
155 em->planes = node;
|
nuclear@0
|
156 return 0;
|
nuclear@0
|
157 }
|
nuclear@0
|
158
|
nuclear@0
|
159 void psys_add_particle(struct psys_emitter *em, struct psys_particle *p)
|
nuclear@0
|
160 {
|
nuclear@0
|
161 p->next = em->plist;
|
nuclear@0
|
162 em->plist = p;
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls)
|
nuclear@0
|
166 {
|
nuclear@0
|
167 em->spawn = func;
|
nuclear@0
|
168 em->spawn_cls = cls;
|
nuclear@0
|
169 }
|
nuclear@0
|
170
|
nuclear@0
|
171 void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls)
|
nuclear@0
|
172 {
|
nuclear@0
|
173 em->update = func;
|
nuclear@0
|
174 em->upd_cls = cls;
|
nuclear@0
|
175 }
|
nuclear@0
|
176
|
nuclear@0
|
177 void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw,
|
nuclear@0
|
178 psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls)
|
nuclear@0
|
179 {
|
nuclear@0
|
180 em->draw = draw;
|
nuclear@0
|
181 em->draw_start = start;
|
nuclear@0
|
182 em->draw_end = end;
|
nuclear@0
|
183 em->draw_cls = cls;
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 /* --- query current state --- */
|
nuclear@0
|
187 vec3_t psys_get_pos(struct psys_emitter *em)
|
nuclear@0
|
188 {
|
nuclear@0
|
189 return em->cur_pos;
|
nuclear@0
|
190 }
|
nuclear@0
|
191
|
nuclear@0
|
192 quat_t psys_get_rot(struct psys_emitter *em)
|
nuclear@0
|
193 {
|
nuclear@0
|
194 return em->cur_rot;
|
nuclear@0
|
195 }
|
nuclear@0
|
196
|
nuclear@0
|
197 float psys_get_rate(struct psys_emitter *em)
|
nuclear@0
|
198 {
|
nuclear@0
|
199 return em->cur_rate;
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202 float psys_get_life(struct psys_emitter *em)
|
nuclear@0
|
203 {
|
nuclear@0
|
204 return em->cur_life;
|
nuclear@0
|
205 }
|
nuclear@0
|
206
|
nuclear@0
|
207 vec3_t psys_get_dir(struct psys_emitter *em)
|
nuclear@0
|
208 {
|
nuclear@0
|
209 return em->cur_dir;
|
nuclear@0
|
210 }
|
nuclear@0
|
211
|
nuclear@1
|
212 vec3_t psys_get_grav(struct psys_emitter *em)
|
nuclear@1
|
213 {
|
nuclear@1
|
214 return em->cur_grav;
|
nuclear@1
|
215 }
|
nuclear@0
|
216
|
nuclear@0
|
217 /* --- update and render --- */
|
nuclear@0
|
218
|
nuclear@0
|
219 void psys_update(struct psys_emitter *em, float tm)
|
nuclear@0
|
220 {
|
nuclear@0
|
221 float dt, spawn_dt;
|
nuclear@0
|
222 int i, spawn_count;
|
nuclear@0
|
223 struct psys_particle *p, pdummy;
|
nuclear@0
|
224 anm_time_t atm;
|
nuclear@0
|
225
|
nuclear@0
|
226 assert(em->spawn && em->update);
|
nuclear@0
|
227
|
nuclear@0
|
228 atm = ANM_SEC2TM(tm);
|
nuclear@0
|
229
|
nuclear@1
|
230 em->cur_rate = anm_get_value(&em->rate, atm);
|
nuclear@0
|
231 dt = tm - em->last_update;
|
nuclear@0
|
232
|
nuclear@0
|
233 /* how many particles to spawn for this interval ? */
|
nuclear@0
|
234 spawn_count = em->cur_rate * dt;
|
nuclear@0
|
235
|
nuclear@0
|
236 #ifndef SUB_UPDATE_POS
|
nuclear@1
|
237 em->cur_pos = anm_get_position(&em->prs, atm);
|
nuclear@0
|
238 #endif
|
nuclear@0
|
239 em->cur_dir = get_v3value(&em->dir, atm);
|
nuclear@0
|
240 em->cur_life = anm_get_value(&em->life, atm);
|
nuclear@1
|
241 em->cur_grav = get_v3value(&em->grav, atm);
|
nuclear@0
|
242
|
nuclear@0
|
243 spawn_dt = dt / (float)spawn_count;
|
nuclear@0
|
244 for(i=0; i<spawn_count; i++) {
|
nuclear@0
|
245 #ifdef SUB_UPDATE_POS
|
nuclear@0
|
246 /* update emitter position for this spawning */
|
nuclear@1
|
247 em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(em->last_update + spawn_dt));
|
nuclear@0
|
248 #endif
|
nuclear@0
|
249
|
nuclear@0
|
250 if(!(p = palloc())) {
|
nuclear@0
|
251 return;
|
nuclear@0
|
252 }
|
nuclear@0
|
253 if(em->spawn(em, p, em->spawn_cls) == -1) {
|
nuclear@0
|
254 pfree(p);
|
nuclear@0
|
255 }
|
nuclear@0
|
256 }
|
nuclear@0
|
257
|
nuclear@0
|
258 /* update all particles */
|
nuclear@0
|
259 p = em->plist;
|
nuclear@0
|
260 while(p) {
|
nuclear@1
|
261 em->update(em, p, tm, dt, em->upd_cls);
|
nuclear@0
|
262 p = p->next;
|
nuclear@0
|
263 }
|
nuclear@0
|
264
|
nuclear@0
|
265 /* cleanup dead particles */
|
nuclear@0
|
266 pdummy.next = em->plist;
|
nuclear@0
|
267 p = &pdummy;
|
nuclear@0
|
268 while(p->next) {
|
nuclear@0
|
269 if(p->next->life <= 0) {
|
nuclear@0
|
270 struct psys_particle *tmp = p->next;
|
nuclear@0
|
271 p->next = p->next->next;
|
nuclear@0
|
272 pfree(tmp);
|
nuclear@0
|
273 } else {
|
nuclear@0
|
274 p = p->next;
|
nuclear@0
|
275 }
|
nuclear@0
|
276 }
|
nuclear@0
|
277 em->plist = pdummy.next;
|
nuclear@0
|
278 }
|
nuclear@0
|
279
|
nuclear@0
|
280 void psys_draw(struct psys_emitter *em)
|
nuclear@0
|
281 {
|
nuclear@0
|
282 struct psys_particle *p;
|
nuclear@0
|
283
|
nuclear@0
|
284 if(em->draw_start) {
|
nuclear@1
|
285 em->draw_start(em, em->draw_cls);
|
nuclear@0
|
286 }
|
nuclear@0
|
287
|
nuclear@0
|
288 p = em->plist;
|
nuclear@0
|
289 while(p) {
|
nuclear@1
|
290 em->draw(em, p, em->draw_cls);
|
nuclear@0
|
291 p = p->next;
|
nuclear@0
|
292 }
|
nuclear@0
|
293
|
nuclear@0
|
294 if(em->draw_end) {
|
nuclear@1
|
295 em->draw_end(em, em->draw_cls);
|
nuclear@0
|
296 }
|
nuclear@0
|
297 }
|
nuclear@0
|
298
|
nuclear@0
|
299 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls)
|
nuclear@0
|
300 {
|
nuclear@0
|
301 p->pos = em->cur_pos;
|
nuclear@0
|
302 p->vel = em->cur_dir;
|
nuclear@0
|
303 p->size = 1.0;
|
nuclear@0
|
304 p->life = em->cur_life;
|
nuclear@0
|
305
|
nuclear@0
|
306 psys_add_particle(em, p);
|
nuclear@0
|
307 return 0;
|
nuclear@0
|
308 }
|
nuclear@0
|
309
|
nuclear@0
|
310 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls)
|
nuclear@0
|
311 {
|
nuclear@1
|
312 vec3_t accel;
|
nuclear@0
|
313
|
nuclear@1
|
314 accel.x = em->cur_grav.x - p->vel.x * em->drag;
|
nuclear@1
|
315 accel.y = em->cur_grav.y - p->vel.y * em->drag;
|
nuclear@1
|
316 accel.z = em->cur_grav.z - p->vel.z * em->drag;
|
nuclear@1
|
317
|
nuclear@1
|
318 p->vel.x += accel.x * dt;
|
nuclear@1
|
319 p->vel.y += accel.y * dt;
|
nuclear@1
|
320 p->vel.z += accel.z * dt;
|
nuclear@0
|
321
|
nuclear@0
|
322 p->pos.x += p->vel.x * dt;
|
nuclear@0
|
323 p->pos.y += p->vel.y * dt;
|
nuclear@0
|
324 p->pos.z += p->vel.z * dt;
|
nuclear@0
|
325 }
|
nuclear@0
|
326
|
nuclear@0
|
327 /* --- v3track helper --- */
|
nuclear@0
|
328
|
nuclear@0
|
329 int init_v3track(struct v3track *v3t)
|
nuclear@0
|
330 {
|
nuclear@0
|
331 if(anm_init_track(&v3t->x) == -1) {
|
nuclear@0
|
332 return -1;
|
nuclear@0
|
333 }
|
nuclear@0
|
334 if(anm_init_track(&v3t->y) == -1) {
|
nuclear@0
|
335 anm_destroy_track(&v3t->x);
|
nuclear@0
|
336 return -1;
|
nuclear@0
|
337 }
|
nuclear@0
|
338 if(anm_init_track(&v3t->z) == -1) {
|
nuclear@0
|
339 anm_destroy_track(&v3t->x);
|
nuclear@0
|
340 anm_destroy_track(&v3t->y);
|
nuclear@0
|
341 return -1;
|
nuclear@0
|
342 }
|
nuclear@0
|
343 return 0;
|
nuclear@0
|
344 }
|
nuclear@0
|
345
|
nuclear@0
|
346 static void destroy_v3track(struct v3track *v3t)
|
nuclear@0
|
347 {
|
nuclear@0
|
348 anm_destroy_track(&v3t->x);
|
nuclear@0
|
349 anm_destroy_track(&v3t->y);
|
nuclear@0
|
350 anm_destroy_track(&v3t->z);
|
nuclear@0
|
351 }
|
nuclear@0
|
352
|
nuclear@0
|
353 static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v)
|
nuclear@0
|
354 {
|
nuclear@0
|
355 anm_set_value(&v3t->x, tm, v.x);
|
nuclear@0
|
356 anm_set_value(&v3t->y, tm, v.y);
|
nuclear@0
|
357 anm_set_value(&v3t->z, tm, v.z);
|
nuclear@0
|
358 }
|
nuclear@0
|
359
|
nuclear@0
|
360 static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm)
|
nuclear@0
|
361 {
|
nuclear@0
|
362 vec3_t v;
|
nuclear@0
|
363 v.x = anm_get_value(&v3t->x, tm);
|
nuclear@0
|
364 v.y = anm_get_value(&v3t->y, tm);
|
nuclear@0
|
365 v.z = anm_get_value(&v3t->z, tm);
|
nuclear@0
|
366 return v;
|
nuclear@0
|
367 }
|
nuclear@0
|
368
|
nuclear@0
|
369 /* --- particle allocation pool --- */
|
nuclear@0
|
370
|
nuclear@0
|
371 static struct psys_particle *palloc(void)
|
nuclear@0
|
372 {
|
nuclear@0
|
373 struct psys_particle *p;
|
nuclear@0
|
374
|
nuclear@0
|
375 pthread_mutex_lock(&pool_lock);
|
nuclear@0
|
376 if(ppool) {
|
nuclear@0
|
377 p = ppool;
|
nuclear@0
|
378 ppool = ppool->next;
|
nuclear@0
|
379 ppool_size--;
|
nuclear@0
|
380 } else {
|
nuclear@0
|
381 p = malloc(sizeof *p);
|
nuclear@0
|
382 }
|
nuclear@0
|
383 pthread_mutex_unlock(&pool_lock);
|
nuclear@0
|
384
|
nuclear@0
|
385 if(p) {
|
nuclear@0
|
386 memset(p, 0, sizeof *p);
|
nuclear@1
|
387 /*reset_pattr(&p->attr);*/
|
nuclear@0
|
388 }
|
nuclear@0
|
389 return p;
|
nuclear@0
|
390 }
|
nuclear@0
|
391
|
nuclear@0
|
392 static void pfree(struct psys_particle *p)
|
nuclear@0
|
393 {
|
nuclear@0
|
394 pthread_mutex_lock(&pool_lock);
|
nuclear@0
|
395 p->next = ppool;
|
nuclear@0
|
396 ppool = p;
|
nuclear@0
|
397 ppool_size++;
|
nuclear@0
|
398 pthread_mutex_unlock(&pool_lock);
|
nuclear@0
|
399 }
|