dungeon_crawler
diff prototype/psys/psys.c @ 67:2560a7ab0243
internalized libanim, libimago2, and libpsys
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 07 Oct 2012 02:04:00 +0300 |
parents | |
children | 45172d087ebe |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/prototype/psys/psys.c Sun Oct 07 02:04:00 2012 +0300 1.3 @@ -0,0 +1,325 @@ 1.4 +#include <stdlib.h> 1.5 +#include <math.h> 1.6 +#include <assert.h> 1.7 +#include <pthread.h> 1.8 +#include "psys.h" 1.9 +#include "psys_gl.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 +/* particle pool */ 1.15 +static struct psys_particle *ppool; 1.16 +static int ppool_size; 1.17 +static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; 1.18 + 1.19 +static struct psys_particle *palloc(void); 1.20 +static void pfree(struct psys_particle *p); 1.21 + 1.22 +/* --- constructors and shit --- */ 1.23 + 1.24 +struct psys_emitter *psys_create(void) 1.25 +{ 1.26 + struct psys_emitter *em; 1.27 + 1.28 + if(!(em = malloc(sizeof *em))) { 1.29 + return 0; 1.30 + } 1.31 + if(psys_init(em) == -1) { 1.32 + free(em); 1.33 + return 0; 1.34 + } 1.35 + return em; 1.36 +} 1.37 + 1.38 +void psys_free(struct psys_emitter *em) 1.39 +{ 1.40 + psys_destroy(em); 1.41 + free(em); 1.42 +} 1.43 + 1.44 +int psys_init(struct psys_emitter *em) 1.45 +{ 1.46 + memset(em, 0, sizeof *em); 1.47 + 1.48 + if(anm_init_node(&em->prs) == -1) { 1.49 + return -1; 1.50 + } 1.51 + if(psys_init_attr(&em->attr) == -1) { 1.52 + anm_destroy_node(&em->prs); 1.53 + return -1; 1.54 + } 1.55 + 1.56 + em->spawn = spawn; 1.57 + em->update = update_particle; 1.58 + 1.59 + em->draw = psys_gl_draw; 1.60 + em->draw_start = psys_gl_draw_start; 1.61 + em->draw_end = psys_gl_draw_end; 1.62 + return 0; 1.63 +} 1.64 + 1.65 +void psys_destroy(struct psys_emitter *em) 1.66 +{ 1.67 + struct psys_particle *part; 1.68 + 1.69 + part = em->plist; 1.70 + while(part) { 1.71 + struct psys_particle *tmp = part; 1.72 + part = part->next; 1.73 + pfree(tmp); 1.74 + } 1.75 + 1.76 + psys_destroy_attr(&em->attr); 1.77 +} 1.78 + 1.79 +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm) 1.80 +{ 1.81 + anm_set_position(&em->prs, pos, ANM_SEC2TM(tm)); 1.82 +} 1.83 + 1.84 +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm) 1.85 +{ 1.86 + anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm)); 1.87 +} 1.88 + 1.89 +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot) 1.90 +{ 1.91 + anm_set_pivot(&em->prs, pivot); 1.92 +} 1.93 + 1.94 +vec3_t psys_get_pos(struct psys_emitter *em, float tm) 1.95 +{ 1.96 + return anm_get_node_position(&em->prs, ANM_SEC2TM(tm)); 1.97 +} 1.98 + 1.99 +quat_t psys_get_rot(struct psys_emitter *em, float tm) 1.100 +{ 1.101 + return anm_get_node_rotation(&em->prs, ANM_SEC2TM(tm)); 1.102 +} 1.103 + 1.104 +vec3_t psys_get_pivot(struct psys_emitter *em) 1.105 +{ 1.106 + return anm_get_pivot(&em->prs); 1.107 +} 1.108 + 1.109 +void psys_clear_collision_planes(struct psys_emitter *em) 1.110 +{ 1.111 + struct psys_plane *plane; 1.112 + 1.113 + plane = em->planes; 1.114 + while(plane) { 1.115 + struct psys_plane *tmp = plane; 1.116 + plane = plane->next; 1.117 + free(tmp); 1.118 + } 1.119 +} 1.120 + 1.121 +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast) 1.122 +{ 1.123 + struct psys_plane *node; 1.124 + 1.125 + if(!(node = malloc(sizeof *node))) { 1.126 + return -1; 1.127 + } 1.128 + node->p = plane; 1.129 + node->elasticity = elast; 1.130 + node->next = em->planes; 1.131 + em->planes = node; 1.132 + return 0; 1.133 +} 1.134 + 1.135 +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p) 1.136 +{ 1.137 + p->next = em->plist; 1.138 + em->plist = p; 1.139 + 1.140 + em->pcount++; 1.141 +} 1.142 + 1.143 +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls) 1.144 +{ 1.145 + em->spawn = func; 1.146 + em->spawn_cls = cls; 1.147 +} 1.148 + 1.149 +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls) 1.150 +{ 1.151 + em->update = func; 1.152 + em->upd_cls = cls; 1.153 +} 1.154 + 1.155 +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, 1.156 + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls) 1.157 +{ 1.158 + em->draw = draw; 1.159 + em->draw_start = start; 1.160 + em->draw_end = end; 1.161 + em->draw_cls = cls; 1.162 +} 1.163 + 1.164 +/* --- update and render --- */ 1.165 + 1.166 +void psys_update(struct psys_emitter *em, float tm) 1.167 +{ 1.168 + float dt, spawn_dt, spawn_tm; 1.169 + int i, spawn_count; 1.170 + struct psys_particle *p, pdummy; 1.171 + anm_time_t atm = ANM_SEC2TM(tm); 1.172 + 1.173 + assert(em->spawn && em->update); 1.174 + 1.175 + dt = tm - em->last_update; 1.176 + if(dt <= 0.0) { 1.177 + return; 1.178 + } 1.179 + 1.180 + psys_eval_attr(&em->attr, atm); 1.181 + 1.182 + /* how many particles to spawn for this interval ? */ 1.183 + em->spawn_acc += psys_get_cur_value(&em->attr.rate) * dt; 1.184 + if(em->spawn_acc >= 1.0) { 1.185 + spawn_count = em->spawn_acc; 1.186 + em->spawn_acc = fmod(em->spawn_acc, 1.0); 1.187 + } else { 1.188 + spawn_count = 0; 1.189 + } 1.190 + 1.191 + spawn_dt = dt / (float)spawn_count; 1.192 + spawn_tm = em->last_update; 1.193 + for(i=0; i<spawn_count; i++) { 1.194 + if(em->attr.max_particles >= 0 && em->pcount >= em->attr.max_particles) { 1.195 + break; 1.196 + } 1.197 + 1.198 + /* update emitter position for this spawning */ 1.199 + em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(spawn_tm)); 1.200 + 1.201 + if(!(p = palloc())) { 1.202 + return; 1.203 + } 1.204 + if(em->spawn(em, p, em->spawn_cls) == -1) { 1.205 + pfree(p); 1.206 + } 1.207 + spawn_tm += spawn_dt; 1.208 + } 1.209 + 1.210 + /* update all particles */ 1.211 + p = em->plist; 1.212 + while(p) { 1.213 + em->update(em, p, tm, dt, em->upd_cls); 1.214 + p = p->next; 1.215 + } 1.216 + 1.217 + /* cleanup dead particles */ 1.218 + pdummy.next = em->plist; 1.219 + p = &pdummy; 1.220 + while(p->next) { 1.221 + if(p->next->life <= 0) { 1.222 + struct psys_particle *tmp = p->next; 1.223 + p->next = p->next->next; 1.224 + pfree(tmp); 1.225 + em->pcount--; 1.226 + } else { 1.227 + p = p->next; 1.228 + } 1.229 + } 1.230 + em->plist = pdummy.next; 1.231 + 1.232 + em->last_update = tm; 1.233 + 1.234 + /*printf("particles: %5d\r", em->pcount);*/ 1.235 +} 1.236 + 1.237 +void psys_draw(struct psys_emitter *em) 1.238 +{ 1.239 + struct psys_particle *p; 1.240 + 1.241 + if(em->draw_start) { 1.242 + em->draw_start(em, em->draw_cls); 1.243 + } 1.244 + 1.245 + p = em->plist; 1.246 + while(p) { 1.247 + em->draw(em, p, em->draw_cls); 1.248 + p = p->next; 1.249 + } 1.250 + 1.251 + if(em->draw_end) { 1.252 + em->draw_end(em, em->draw_cls); 1.253 + } 1.254 +} 1.255 + 1.256 +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls) 1.257 +{ 1.258 + struct psys_rnd3 rpos; 1.259 + rpos.value = em->cur_pos; 1.260 + rpos.range = psys_get_cur_value3(&em->attr.spawn_range); 1.261 + 1.262 + p->pos = psys_eval_rnd3(&rpos); 1.263 + p->vel = psys_eval_anm_rnd3(&em->attr.dir, PSYS_EVAL_CUR); 1.264 + p->base_size = psys_eval_anm_rnd(&em->attr.size, PSYS_EVAL_CUR); 1.265 + p->max_life = p->life = psys_eval_anm_rnd(&em->attr.life, PSYS_EVAL_CUR); 1.266 + 1.267 + p->pattr = &em->attr.part_attr; 1.268 + 1.269 + psys_add_particle(em, p); 1.270 + return 0; 1.271 +} 1.272 + 1.273 +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls) 1.274 +{ 1.275 + vec3_t accel, grav; 1.276 + anm_time_t t; 1.277 + 1.278 + grav = psys_get_cur_value3(&em->attr.grav); 1.279 + 1.280 + accel.x = grav.x - p->vel.x * em->attr.drag; 1.281 + accel.y = grav.y - p->vel.y * em->attr.drag; 1.282 + accel.z = grav.z - p->vel.z * em->attr.drag; 1.283 + 1.284 + p->vel.x += accel.x * dt; 1.285 + p->vel.y += accel.y * dt; 1.286 + p->vel.z += accel.z * dt; 1.287 + 1.288 + p->pos.x += p->vel.x * dt; 1.289 + p->pos.y += p->vel.y * dt; 1.290 + p->pos.z += p->vel.z * dt; 1.291 + 1.292 + /* update particle attributes */ 1.293 + t = (anm_time_t)(1000.0 * (p->max_life - p->life) / p->max_life); 1.294 + 1.295 + p->color = psys_get_value3(&p->pattr->color, t); 1.296 + p->alpha = psys_get_value(&p->pattr->alpha, t); 1.297 + p->size = p->base_size * psys_get_value(&p->pattr->size, t); 1.298 + 1.299 + p->life -= dt; 1.300 +} 1.301 + 1.302 +/* --- particle allocation pool --- */ 1.303 + 1.304 +static struct psys_particle *palloc(void) 1.305 +{ 1.306 + struct psys_particle *p; 1.307 + 1.308 + pthread_mutex_lock(&pool_lock); 1.309 + if(ppool) { 1.310 + p = ppool; 1.311 + ppool = ppool->next; 1.312 + ppool_size--; 1.313 + } else { 1.314 + p = malloc(sizeof *p); 1.315 + } 1.316 + pthread_mutex_unlock(&pool_lock); 1.317 + 1.318 + return p; 1.319 +} 1.320 + 1.321 +static void pfree(struct psys_particle *p) 1.322 +{ 1.323 + pthread_mutex_lock(&pool_lock); 1.324 + p->next = ppool; 1.325 + ppool = p; 1.326 + ppool_size++; 1.327 + pthread_mutex_unlock(&pool_lock); 1.328 +}