libpsys
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/psys.c Sat Sep 24 07:22:07 2011 +0300 1.3 @@ -0,0 +1,374 @@ 1.4 +#include <stdlib.h> 1.5 +#include <math.h> 1.6 +#include <assert.h> 1.7 +#include <pthread.h> 1.8 +#include <vmath.h> 1.9 +#include "psys_impl.h" 1.10 + 1.11 +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls); 1.12 +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls); 1.13 + 1.14 +static int init_v3track(struct v3track *v3t); 1.15 +static void destroy_v3track(struct v3track *v3t); 1.16 +static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v); 1.17 +static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm); 1.18 + 1.19 +/* particle pool */ 1.20 +static struct psys_particle *ppool; 1.21 +static int ppool_size; 1.22 +static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; 1.23 + 1.24 +static struct psys_particle *palloc(void); 1.25 +static void pfree(struct psys_particle *p); 1.26 + 1.27 +/* --- constructors and shit --- */ 1.28 + 1.29 +struct psys_emitter *psys_create(void) 1.30 +{ 1.31 + struct psys_emitter *em; 1.32 + 1.33 + if(!(em = malloc(sizeof *em))) { 1.34 + return 0; 1.35 + } 1.36 + if(psys_init(em) == -1) { 1.37 + free(em); 1.38 + return 0; 1.39 + } 1.40 + return em; 1.41 +} 1.42 + 1.43 +void psys_free(struct psys_emitter *em) 1.44 +{ 1.45 + psys_destroy(em); 1.46 + free(em); 1.47 +} 1.48 + 1.49 +int psys_init(struct psys_emitter *em) 1.50 +{ 1.51 + memset(em, 0, sizeof *em); 1.52 + 1.53 + if(anm_init_node(&em->prs) == -1) { 1.54 + return -1; 1.55 + } 1.56 + if(anm_init_track(&em->rate) == -1) { 1.57 + anm_destroy_node(&em->prs); 1.58 + return -1; 1.59 + } 1.60 + if(init_v3track(&em->dir) == -1) { 1.61 + anm_destroy_node(&em->prs); 1.62 + anm_destroy_track(&em->rate); 1.63 + return -1; 1.64 + } 1.65 + 1.66 + em->spawn = spawn; 1.67 + em->update = update_particle; 1.68 + 1.69 + em->draw = psys_gl_draw; 1.70 + em->draw_start = psys_gl_draw_start; 1.71 + em->draw_end = psys_gl_draw_end; 1.72 + 1.73 + return 0; 1.74 +} 1.75 + 1.76 +void psys_destroy(struct psys_emitter *em) 1.77 +{ 1.78 + struct psys_particle *part; 1.79 + 1.80 + part = em->plist; 1.81 + while(part) { 1.82 + struct psys_particle *tmp = part; 1.83 + part = part->next; 1.84 + pfree(tmp); 1.85 + } 1.86 + 1.87 + anm_destroy_node(&em->prs); 1.88 + anm_destroy_track(&em->rate); 1.89 + destroy_v3track(&em->dir); 1.90 +} 1.91 + 1.92 +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm) 1.93 +{ 1.94 + anm_set_position(&em->prs, pos, ANM_SEC2TM(tm)); 1.95 +} 1.96 + 1.97 +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm) 1.98 +{ 1.99 + anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm)); 1.100 +} 1.101 + 1.102 +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot) 1.103 +{ 1.104 + anm_set_pivot(&em->prs, pivot); 1.105 +} 1.106 + 1.107 +void psys_set_rate(struct psys_emitter *em, float rate, float tm) 1.108 +{ 1.109 + anm_set_value(&em->rate, ANM_SEC2TM(tm), rate); 1.110 +} 1.111 + 1.112 +void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm) 1.113 +{ 1.114 + set_v3value(&em->dir, ANM_SEC2TM(tm), dir); 1.115 +} 1.116 + 1.117 + 1.118 +void psys_clear_collision_planes(struct psys_emitter *em) 1.119 +{ 1.120 + struct col_plane *plane; 1.121 + 1.122 + plane = em->planes; 1.123 + while(plane) { 1.124 + struct col_plane *tmp = plane; 1.125 + plane = plane->next; 1.126 + pfree(tmp); 1.127 + } 1.128 +} 1.129 + 1.130 +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast) 1.131 +{ 1.132 + struct col_plane *node; 1.133 + 1.134 + if(!(node = malloc(sizeof *node))) { 1.135 + return -1; 1.136 + } 1.137 + node->p = plane; 1.138 + node->elasticity = elast; 1.139 + node->next = em->planes; 1.140 + em->planes = node; 1.141 + return 0; 1.142 +} 1.143 + 1.144 +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p) 1.145 +{ 1.146 + p->next = em->plist; 1.147 + em->plist = p; 1.148 +} 1.149 + 1.150 +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls) 1.151 +{ 1.152 + em->spawn = func; 1.153 + em->spawn_cls = cls; 1.154 +} 1.155 + 1.156 +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls) 1.157 +{ 1.158 + em->update = func; 1.159 + em->upd_cls = cls; 1.160 +} 1.161 + 1.162 +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, 1.163 + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls) 1.164 +{ 1.165 + em->draw = draw; 1.166 + em->draw_start = start; 1.167 + em->draw_end = end; 1.168 + em->draw_cls = cls; 1.169 +} 1.170 + 1.171 +/* --- query current state --- */ 1.172 +vec3_t psys_get_pos(struct psys_emitter *em) 1.173 +{ 1.174 + return em->cur_pos; 1.175 +} 1.176 + 1.177 +quat_t psys_get_rot(struct psys_emitter *em) 1.178 +{ 1.179 + return em->cur_rot; 1.180 +} 1.181 + 1.182 +float psys_get_rate(struct psys_emitter *em) 1.183 +{ 1.184 + return em->cur_rate; 1.185 +} 1.186 + 1.187 +float psys_get_life(struct psys_emitter *em) 1.188 +{ 1.189 + return em->cur_life; 1.190 +} 1.191 + 1.192 +vec3_t psys_get_dir(struct psys_emitter *em) 1.193 +{ 1.194 + return em->cur_dir; 1.195 +} 1.196 + 1.197 + 1.198 +/* --- update and render --- */ 1.199 + 1.200 +void psys_update(struct psys_emitter *em, float tm) 1.201 +{ 1.202 + float dt, spawn_dt; 1.203 + int i, spawn_count; 1.204 + struct psys_particle *p, pdummy; 1.205 + anm_time_t atm; 1.206 + 1.207 + assert(em->spawn && em->update); 1.208 + 1.209 + atm = ANM_SEC2TM(tm); 1.210 + 1.211 + em->cur_rate = anm_get_value(&em->rate, atm) 1.212 + dt = tm - em->last_update; 1.213 + 1.214 + /* how many particles to spawn for this interval ? */ 1.215 + spawn_count = em->cur_rate * dt; 1.216 + 1.217 +#ifndef SUB_UPDATE_POS 1.218 + em->pos = anm_get_position(&em->prs, atm); 1.219 +#endif 1.220 + em->cur_dir = get_v3value(&em->dir, atm); 1.221 + em->cur_life = anm_get_value(&em->life, atm); 1.222 + 1.223 + spawn_dt = dt / (float)spawn_count; 1.224 + for(i=0; i<spawn_count; i++) { 1.225 +#ifdef SUB_UPDATE_POS 1.226 + /* update emitter position for this spawning */ 1.227 + em->pos = anm_get_position(&em->prs, ANM_SEC2TM(em->last_update + spawn_dt)); 1.228 +#endif 1.229 + 1.230 + if(!(p = palloc())) { 1.231 + return; 1.232 + } 1.233 + if(em->spawn(em, p, em->spawn_cls) == -1) { 1.234 + pfree(p); 1.235 + } 1.236 + } 1.237 + 1.238 + /* update all particles */ 1.239 + p = em->plist; 1.240 + while(p) { 1.241 + em->update(em, p, tm, dt, upd_cls); 1.242 + p = p->next; 1.243 + } 1.244 + 1.245 + /* cleanup dead particles */ 1.246 + pdummy.next = em->plist; 1.247 + p = &pdummy; 1.248 + while(p->next) { 1.249 + if(p->next->life <= 0) { 1.250 + struct psys_particle *tmp = p->next; 1.251 + p->next = p->next->next; 1.252 + pfree(tmp); 1.253 + } else { 1.254 + p = p->next; 1.255 + } 1.256 + } 1.257 + em->plist = pdummy.next; 1.258 +} 1.259 + 1.260 +void psys_draw(struct psys_emitter *em) 1.261 +{ 1.262 + struct psys_particle *p; 1.263 + 1.264 + if(em->draw_start) { 1.265 + em->draw_start(em, em->cls); 1.266 + } 1.267 + 1.268 + p = em->plist; 1.269 + while(p) { 1.270 + em->draw(em, p, em->cls); 1.271 + p = p->next; 1.272 + } 1.273 + 1.274 + if(em->draw_end) { 1.275 + em->draw_end(em, em->cls); 1.276 + } 1.277 +} 1.278 + 1.279 +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls) 1.280 +{ 1.281 + p->pos = em->cur_pos; 1.282 + p->vel = em->cur_dir; 1.283 + p->size = 1.0; 1.284 + p->life = em->cur_life; 1.285 + 1.286 + psys_add_particle(em, p); 1.287 + return 0; 1.288 +} 1.289 + 1.290 +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls) 1.291 +{ 1.292 + vec3_t forces; 1.293 + 1.294 + forces.x = em->cur_grav.x * p->mass - p->vel.x * em->drag; 1.295 + forces.y = em->cur_grav.y * p->mass - p->vel.y * em->drag; 1.296 + forces.z = em->cur_grav.z * p->mass - p->vel.z * em->drag; 1.297 + 1.298 + p->pos.x += p->vel.x * dt; 1.299 + p->pos.y += p->vel.y * dt; 1.300 + p->pos.z += p->vel.z * dt; 1.301 + 1.302 + 1.303 +} 1.304 + 1.305 +/* --- v3track helper --- */ 1.306 + 1.307 +int init_v3track(struct v3track *v3t) 1.308 +{ 1.309 + if(anm_init_track(&v3t->x) == -1) { 1.310 + return -1; 1.311 + } 1.312 + if(anm_init_track(&v3t->y) == -1) { 1.313 + anm_destroy_track(&v3t->x); 1.314 + return -1; 1.315 + } 1.316 + if(anm_init_track(&v3t->z) == -1) { 1.317 + anm_destroy_track(&v3t->x); 1.318 + anm_destroy_track(&v3t->y); 1.319 + return -1; 1.320 + } 1.321 + return 0; 1.322 +} 1.323 + 1.324 +static void destroy_v3track(struct v3track *v3t) 1.325 +{ 1.326 + anm_destroy_track(&v3t->x); 1.327 + anm_destroy_track(&v3t->y); 1.328 + anm_destroy_track(&v3t->z); 1.329 +} 1.330 + 1.331 +static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v) 1.332 +{ 1.333 + anm_set_value(&v3t->x, tm, v.x); 1.334 + anm_set_value(&v3t->y, tm, v.y); 1.335 + anm_set_value(&v3t->z, tm, v.z); 1.336 +} 1.337 + 1.338 +static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm) 1.339 +{ 1.340 + vec3_t v; 1.341 + v.x = anm_get_value(&v3t->x, tm); 1.342 + v.y = anm_get_value(&v3t->y, tm); 1.343 + v.z = anm_get_value(&v3t->z, tm); 1.344 + return v; 1.345 +} 1.346 + 1.347 +/* --- particle allocation pool --- */ 1.348 + 1.349 +static struct psys_particle *palloc(void) 1.350 +{ 1.351 + struct psys_particle *p; 1.352 + 1.353 + pthread_mutex_lock(&pool_lock); 1.354 + if(ppool) { 1.355 + p = ppool; 1.356 + ppool = ppool->next; 1.357 + ppool_size--; 1.358 + } else { 1.359 + p = malloc(sizeof *p); 1.360 + } 1.361 + pthread_mutex_unlock(&pool_lock); 1.362 + 1.363 + if(p) { 1.364 + memset(p, 0, sizeof *p); 1.365 + reset_pattr(&p->attr); 1.366 + } 1.367 + return p; 1.368 +} 1.369 + 1.370 +static void pfree(struct psys_particle *p) 1.371 +{ 1.372 + pthread_mutex_lock(&pool_lock); 1.373 + p->next = ppool; 1.374 + ppool = p; 1.375 + ppool_size++; 1.376 + pthread_mutex_unlock(&pool_lock); 1.377 +}