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