libpsys

view src/psys.c @ 6:d774738f50f6

almost finished with the reorg (2)
author John Tsiombikas <nuclear@mutantstargoat.com>
date Tue, 27 Sep 2011 07:42:54 +0300
parents 0fe624ffcb4f
children 3c0a306c5f01
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.h"
7 #include "psys_gl.h"
9 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls);
10 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls);
12 /* particle pool */
13 static struct psys_particle *ppool;
14 static int ppool_size;
15 static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER;
17 static struct psys_particle *palloc(void);
18 static void pfree(struct psys_particle *p);
20 /* --- constructors and shit --- */
22 struct psys_emitter *psys_create(void)
23 {
24 struct psys_emitter *em;
26 if(!(em = malloc(sizeof *em))) {
27 return 0;
28 }
29 if(psys_init(em) == -1) {
30 free(em);
31 return 0;
32 }
33 return em;
34 }
36 void psys_free(struct psys_emitter *em)
37 {
38 psys_destroy(em);
39 free(em);
40 }
42 int psys_init(struct psys_emitter *em)
43 {
44 memset(em, 0, sizeof *em);
46 if(anm_init_node(&em->prs) == -1) {
47 return -1;
48 }
49 if(psys_init_attr(&em->attr) == -1) {
50 anm_destroy_node(&em->prs);
51 return -1;
52 }
54 em->spawn = spawn;
55 em->update = update_particle;
57 em->draw = psys_gl_draw;
58 em->draw_start = psys_gl_draw_start;
59 em->draw_end = psys_gl_draw_end;
60 return 0;
61 }
63 void psys_destroy(struct psys_emitter *em)
64 {
65 struct psys_particle *part;
67 part = em->plist;
68 while(part) {
69 struct psys_particle *tmp = part;
70 part = part->next;
71 pfree(tmp);
72 }
74 psys_destroy_attr(&em->attr);
75 }
77 void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm)
78 {
79 anm_set_position(&em->prs, pos, ANM_SEC2TM(tm));
80 }
82 void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm)
83 {
84 anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm));
85 }
87 void psys_set_pivot(struct psys_emitter *em, vec3_t pivot)
88 {
89 anm_set_pivot(&em->prs, pivot);
90 }
92 void psys_clear_collision_planes(struct psys_emitter *em)
93 {
94 struct psys_plane *plane;
96 plane = em->planes;
97 while(plane) {
98 struct psys_plane *tmp = plane;
99 plane = plane->next;
100 free(tmp);
101 }
102 }
104 int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast)
105 {
106 struct psys_plane *node;
108 if(!(node = malloc(sizeof *node))) {
109 return -1;
110 }
111 node->p = plane;
112 node->elasticity = elast;
113 node->next = em->planes;
114 em->planes = node;
115 return 0;
116 }
118 void psys_add_particle(struct psys_emitter *em, struct psys_particle *p)
119 {
120 p->next = em->plist;
121 em->plist = p;
123 em->pcount++;
124 }
126 void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls)
127 {
128 em->spawn = func;
129 em->spawn_cls = cls;
130 }
132 void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls)
133 {
134 em->update = func;
135 em->upd_cls = cls;
136 }
138 void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw,
139 psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls)
140 {
141 em->draw = draw;
142 em->draw_start = start;
143 em->draw_end = end;
144 em->draw_cls = cls;
145 }
147 /* --- update and render --- */
149 void psys_update(struct psys_emitter *em, float tm)
150 {
151 float dt, spawn_dt, spawn_tm;
152 int i, spawn_count;
153 struct psys_particle *p, pdummy;
154 anm_time_t atm = ANM_SEC2TM(tm);
156 assert(em->spawn && em->update);
158 dt = tm - em->last_update;
159 if(dt <= 0.0) {
160 return;
161 }
163 psys_eval_attr(&em->attr, atm);
165 /* how many particles to spawn for this interval ? */
166 em->spawn_acc += psys_get_cur_value(&em->attr.rate) * dt;
167 if(em->spawn_acc >= 1.0) {
168 spawn_count = em->spawn_acc;
169 em->spawn_acc = fmod(em->spawn_acc, 1.0);
170 } else {
171 spawn_count = 0;
172 }
174 spawn_dt = dt / (float)spawn_count;
175 spawn_tm = em->last_update;
176 for(i=0; i<spawn_count; i++) {
177 if(em->pcount >= em->attr.max_particles) {
178 break;
179 }
181 /* update emitter position for this spawning */
182 em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(spawn_tm));
184 if(!(p = palloc())) {
185 return;
186 }
187 if(em->spawn(em, p, em->spawn_cls) == -1) {
188 pfree(p);
189 }
190 spawn_tm += spawn_dt;
191 }
193 /* update all particles */
194 p = em->plist;
195 while(p) {
196 em->update(em, p, tm, dt, em->upd_cls);
197 p = p->next;
198 }
200 /* cleanup dead particles */
201 pdummy.next = em->plist;
202 p = &pdummy;
203 while(p->next) {
204 if(p->next->life <= 0) {
205 struct psys_particle *tmp = p->next;
206 p->next = p->next->next;
207 pfree(tmp);
208 } else {
209 p = p->next;
210 }
211 }
212 em->plist = pdummy.next;
214 em->last_update = tm;
215 }
217 void psys_draw(struct psys_emitter *em)
218 {
219 struct psys_particle *p;
221 if(em->draw_start) {
222 em->draw_start(em, em->draw_cls);
223 }
225 p = em->plist;
226 while(p) {
227 em->draw(em, p, em->draw_cls);
228 p = p->next;
229 }
231 if(em->draw_end) {
232 em->draw_end(em, em->draw_cls);
233 }
234 }
236 static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls)
237 {
238 struct psys_rnd3 rpos;
239 rpos.value = em->cur_pos;
240 rpos.range = psys_get_cur_value3(&em->attr.spawn_range);
242 p->pos = psys_eval_rnd3(&rpos);
243 p->vel = psys_eval_anm_rnd3(&em->attr.dir, PSYS_EVAL_CUR);
244 p->size = psys_eval_anm_rnd(&em->attr.size, PSYS_EVAL_CUR);
245 p->life = psys_eval_anm_rnd(&em->attr.life, PSYS_EVAL_CUR);
247 psys_add_particle(em, p);
248 return 0;
249 }
251 static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls)
252 {
253 vec3_t accel, grav;
255 grav = psys_get_cur_value3(&em->attr.grav);
257 accel.x = grav.x - p->vel.x * em->attr.drag;
258 accel.y = grav.y - p->vel.y * em->attr.drag;
259 accel.z = grav.z - p->vel.z * em->attr.drag;
261 p->vel.x += accel.x * dt;
262 p->vel.y += accel.y * dt;
263 p->vel.z += accel.z * dt;
265 p->pos.x += p->vel.x * dt;
266 p->pos.y += p->vel.y * dt;
267 p->pos.z += p->vel.z * dt;
269 p->life -= dt;
270 }
272 /* --- particle allocation pool --- */
274 static struct psys_particle *palloc(void)
275 {
276 struct psys_particle *p;
278 pthread_mutex_lock(&pool_lock);
279 if(ppool) {
280 p = ppool;
281 ppool = ppool->next;
282 ppool_size--;
283 } else {
284 p = malloc(sizeof *p);
285 }
286 pthread_mutex_unlock(&pool_lock);
288 return p;
289 }
291 static void pfree(struct psys_particle *p)
292 {
293 pthread_mutex_lock(&pool_lock);
294 p->next = ppool;
295 ppool = p;
296 ppool_size++;
297 pthread_mutex_unlock(&pool_lock);
298 }