libpsys

view src/psys.c @ 0:1c8eb90a6989

initial commit
author John Tsiombikas <nuclear@mutantstargoat.com>
date Sat, 24 Sep 2011 07:22:07 +0300
parents
children 874a942853ad
line source
1 #include <stdlib.h>
2 #include <math.h>
3 #include <assert.h>
4 #include <pthread.h>
5 #include <vmath.h>
6 #include "psys_impl.h"
8 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls);
9 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls);
11 static int init_v3track(struct v3track *v3t);
12 static void destroy_v3track(struct v3track *v3t);
13 static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v);
14 static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm);
16 /* particle pool */
17 static struct psys_particle *ppool;
18 static int ppool_size;
19 static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER;
21 static struct psys_particle *palloc(void);
22 static void pfree(struct psys_particle *p);
24 /* --- constructors and shit --- */
26 struct psys_emitter *psys_create(void)
27 {
28 struct psys_emitter *em;
30 if(!(em = malloc(sizeof *em))) {
31 return 0;
32 }
33 if(psys_init(em) == -1) {
34 free(em);
35 return 0;
36 }
37 return em;
38 }
40 void psys_free(struct psys_emitter *em)
41 {
42 psys_destroy(em);
43 free(em);
44 }
46 int psys_init(struct psys_emitter *em)
47 {
48 memset(em, 0, sizeof *em);
50 if(anm_init_node(&em->prs) == -1) {
51 return -1;
52 }
53 if(anm_init_track(&em->rate) == -1) {
54 anm_destroy_node(&em->prs);
55 return -1;
56 }
57 if(init_v3track(&em->dir) == -1) {
58 anm_destroy_node(&em->prs);
59 anm_destroy_track(&em->rate);
60 return -1;
61 }
63 em->spawn = spawn;
64 em->update = update_particle;
66 em->draw = psys_gl_draw;
67 em->draw_start = psys_gl_draw_start;
68 em->draw_end = psys_gl_draw_end;
70 return 0;
71 }
73 void psys_destroy(struct psys_emitter *em)
74 {
75 struct psys_particle *part;
77 part = em->plist;
78 while(part) {
79 struct psys_particle *tmp = part;
80 part = part->next;
81 pfree(tmp);
82 }
84 anm_destroy_node(&em->prs);
85 anm_destroy_track(&em->rate);
86 destroy_v3track(&em->dir);
87 }
89 void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm)
90 {
91 anm_set_position(&em->prs, pos, ANM_SEC2TM(tm));
92 }
94 void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm)
95 {
96 anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm));
97 }
99 void psys_set_pivot(struct psys_emitter *em, vec3_t pivot)
100 {
101 anm_set_pivot(&em->prs, pivot);
102 }
104 void psys_set_rate(struct psys_emitter *em, float rate, float tm)
105 {
106 anm_set_value(&em->rate, ANM_SEC2TM(tm), rate);
107 }
109 void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm)
110 {
111 set_v3value(&em->dir, ANM_SEC2TM(tm), dir);
112 }
115 void psys_clear_collision_planes(struct psys_emitter *em)
116 {
117 struct col_plane *plane;
119 plane = em->planes;
120 while(plane) {
121 struct col_plane *tmp = plane;
122 plane = plane->next;
123 pfree(tmp);
124 }
125 }
127 int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast)
128 {
129 struct col_plane *node;
131 if(!(node = malloc(sizeof *node))) {
132 return -1;
133 }
134 node->p = plane;
135 node->elasticity = elast;
136 node->next = em->planes;
137 em->planes = node;
138 return 0;
139 }
141 void psys_add_particle(struct psys_emitter *em, struct psys_particle *p)
142 {
143 p->next = em->plist;
144 em->plist = p;
145 }
147 void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls)
148 {
149 em->spawn = func;
150 em->spawn_cls = cls;
151 }
153 void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls)
154 {
155 em->update = func;
156 em->upd_cls = cls;
157 }
159 void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw,
160 psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls)
161 {
162 em->draw = draw;
163 em->draw_start = start;
164 em->draw_end = end;
165 em->draw_cls = cls;
166 }
168 /* --- query current state --- */
169 vec3_t psys_get_pos(struct psys_emitter *em)
170 {
171 return em->cur_pos;
172 }
174 quat_t psys_get_rot(struct psys_emitter *em)
175 {
176 return em->cur_rot;
177 }
179 float psys_get_rate(struct psys_emitter *em)
180 {
181 return em->cur_rate;
182 }
184 float psys_get_life(struct psys_emitter *em)
185 {
186 return em->cur_life;
187 }
189 vec3_t psys_get_dir(struct psys_emitter *em)
190 {
191 return em->cur_dir;
192 }
195 /* --- update and render --- */
197 void psys_update(struct psys_emitter *em, float tm)
198 {
199 float dt, spawn_dt;
200 int i, spawn_count;
201 struct psys_particle *p, pdummy;
202 anm_time_t atm;
204 assert(em->spawn && em->update);
206 atm = ANM_SEC2TM(tm);
208 em->cur_rate = anm_get_value(&em->rate, atm)
209 dt = tm - em->last_update;
211 /* how many particles to spawn for this interval ? */
212 spawn_count = em->cur_rate * dt;
214 #ifndef SUB_UPDATE_POS
215 em->pos = anm_get_position(&em->prs, atm);
216 #endif
217 em->cur_dir = get_v3value(&em->dir, atm);
218 em->cur_life = anm_get_value(&em->life, atm);
220 spawn_dt = dt / (float)spawn_count;
221 for(i=0; i<spawn_count; i++) {
222 #ifdef SUB_UPDATE_POS
223 /* update emitter position for this spawning */
224 em->pos = anm_get_position(&em->prs, ANM_SEC2TM(em->last_update + spawn_dt));
225 #endif
227 if(!(p = palloc())) {
228 return;
229 }
230 if(em->spawn(em, p, em->spawn_cls) == -1) {
231 pfree(p);
232 }
233 }
235 /* update all particles */
236 p = em->plist;
237 while(p) {
238 em->update(em, p, tm, dt, upd_cls);
239 p = p->next;
240 }
242 /* cleanup dead particles */
243 pdummy.next = em->plist;
244 p = &pdummy;
245 while(p->next) {
246 if(p->next->life <= 0) {
247 struct psys_particle *tmp = p->next;
248 p->next = p->next->next;
249 pfree(tmp);
250 } else {
251 p = p->next;
252 }
253 }
254 em->plist = pdummy.next;
255 }
257 void psys_draw(struct psys_emitter *em)
258 {
259 struct psys_particle *p;
261 if(em->draw_start) {
262 em->draw_start(em, em->cls);
263 }
265 p = em->plist;
266 while(p) {
267 em->draw(em, p, em->cls);
268 p = p->next;
269 }
271 if(em->draw_end) {
272 em->draw_end(em, em->cls);
273 }
274 }
276 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls)
277 {
278 p->pos = em->cur_pos;
279 p->vel = em->cur_dir;
280 p->size = 1.0;
281 p->life = em->cur_life;
283 psys_add_particle(em, p);
284 return 0;
285 }
287 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls)
288 {
289 vec3_t forces;
291 forces.x = em->cur_grav.x * p->mass - p->vel.x * em->drag;
292 forces.y = em->cur_grav.y * p->mass - p->vel.y * em->drag;
293 forces.z = em->cur_grav.z * p->mass - p->vel.z * em->drag;
295 p->pos.x += p->vel.x * dt;
296 p->pos.y += p->vel.y * dt;
297 p->pos.z += p->vel.z * dt;
300 }
302 /* --- v3track helper --- */
304 int init_v3track(struct v3track *v3t)
305 {
306 if(anm_init_track(&v3t->x) == -1) {
307 return -1;
308 }
309 if(anm_init_track(&v3t->y) == -1) {
310 anm_destroy_track(&v3t->x);
311 return -1;
312 }
313 if(anm_init_track(&v3t->z) == -1) {
314 anm_destroy_track(&v3t->x);
315 anm_destroy_track(&v3t->y);
316 return -1;
317 }
318 return 0;
319 }
321 static void destroy_v3track(struct v3track *v3t)
322 {
323 anm_destroy_track(&v3t->x);
324 anm_destroy_track(&v3t->y);
325 anm_destroy_track(&v3t->z);
326 }
328 static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v)
329 {
330 anm_set_value(&v3t->x, tm, v.x);
331 anm_set_value(&v3t->y, tm, v.y);
332 anm_set_value(&v3t->z, tm, v.z);
333 }
335 static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm)
336 {
337 vec3_t v;
338 v.x = anm_get_value(&v3t->x, tm);
339 v.y = anm_get_value(&v3t->y, tm);
340 v.z = anm_get_value(&v3t->z, tm);
341 return v;
342 }
344 /* --- particle allocation pool --- */
346 static struct psys_particle *palloc(void)
347 {
348 struct psys_particle *p;
350 pthread_mutex_lock(&pool_lock);
351 if(ppool) {
352 p = ppool;
353 ppool = ppool->next;
354 ppool_size--;
355 } else {
356 p = malloc(sizeof *p);
357 }
358 pthread_mutex_unlock(&pool_lock);
360 if(p) {
361 memset(p, 0, sizeof *p);
362 reset_pattr(&p->attr);
363 }
364 return p;
365 }
367 static void pfree(struct psys_particle *p)
368 {
369 pthread_mutex_lock(&pool_lock);
370 p->next = ppool;
371 ppool = p;
372 ppool_size++;
373 pthread_mutex_unlock(&pool_lock);
374 }