dungeon_crawler
diff prototype/psys/pattr.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/pattr.c Sun Oct 07 02:04:00 2012 +0300 1.3 @@ -0,0 +1,371 @@ 1.4 +#define _GNU_SOURCE 1.5 +#include <stdio.h> 1.6 +#include <stdlib.h> 1.7 +#include <string.h> 1.8 +#include <errno.h> 1.9 +#include <ctype.h> 1.10 + 1.11 +#ifdef _MSC_VER 1.12 +#include <malloc.h> 1.13 +#else 1.14 +#include <alloca.h> 1.15 +#endif 1.16 + 1.17 +#include "pattr.h" 1.18 +#include "psys_gl.h" 1.19 + 1.20 +enum { 1.21 + OPT_STR, 1.22 + OPT_NUM, 1.23 + OPT_NUM_RANGE, 1.24 + OPT_VEC, 1.25 + OPT_VEC_RANGE 1.26 +}; 1.27 + 1.28 +struct cfgopt { 1.29 + char *name; 1.30 + int type; 1.31 + long tm; 1.32 + char *valstr; 1.33 + vec3_t val, valrng; 1.34 +}; 1.35 + 1.36 +static int init_particle_attr(struct psys_particle_attributes *pattr); 1.37 +static void destroy_particle_attr(struct psys_particle_attributes *pattr); 1.38 +static struct cfgopt *get_cfg_opt(const char *line); 1.39 +static void release_cfg_opt(struct cfgopt *opt); 1.40 +static char *stripspace(char *str); 1.41 + 1.42 +static void *tex_cls; 1.43 +static unsigned int (*load_texture)(const char*, void*) = psys_gl_load_texture; 1.44 +static void (*unload_texture)(unsigned int, void*) = psys_gl_unload_texture; 1.45 + 1.46 + 1.47 +void psys_texture_loader(unsigned int (*load)(const char*, void*), void (*unload)(unsigned int, void*), void *cls) 1.48 +{ 1.49 + load_texture = load; 1.50 + unload_texture = unload; 1.51 + tex_cls = cls; 1.52 +} 1.53 + 1.54 +struct psys_attributes *psys_create_attr(void) 1.55 +{ 1.56 + struct psys_attributes *attr = malloc(sizeof *attr); 1.57 + if(attr) { 1.58 + if(psys_init_attr(attr) == -1) { 1.59 + free(attr); 1.60 + attr = 0; 1.61 + } 1.62 + } 1.63 + return attr; 1.64 +} 1.65 + 1.66 +void psys_free_attr(struct psys_attributes *attr) 1.67 +{ 1.68 + psys_destroy_attr(attr); 1.69 + free(attr); 1.70 +} 1.71 + 1.72 +int psys_init_attr(struct psys_attributes *attr) 1.73 +{ 1.74 + memset(attr, 0, sizeof *attr); 1.75 + 1.76 + if(psys_init_track3(&attr->spawn_range) == -1) 1.77 + goto err; 1.78 + if(psys_init_track(&attr->rate) == -1) 1.79 + goto err; 1.80 + if(psys_init_anm_rnd(&attr->life) == -1) 1.81 + goto err; 1.82 + if(psys_init_anm_rnd(&attr->size) == -1) 1.83 + goto err; 1.84 + if(psys_init_anm_rnd3(&attr->dir) == -1) 1.85 + goto err; 1.86 + if(psys_init_track3(&attr->grav) == -1) 1.87 + goto err; 1.88 + 1.89 + if(init_particle_attr(&attr->part_attr) == -1) 1.90 + goto err; 1.91 + 1.92 + attr->max_particles = -1; 1.93 + 1.94 + anm_set_track_default(&attr->size.value.trk, 1.0); 1.95 + anm_set_track_default(&attr->life.value.trk, 1.0); 1.96 + 1.97 + return 0; 1.98 + 1.99 +err: 1.100 + psys_destroy_attr(attr); 1.101 + return -1; 1.102 +} 1.103 + 1.104 + 1.105 +static int init_particle_attr(struct psys_particle_attributes *pattr) 1.106 +{ 1.107 + if(psys_init_track3(&pattr->color) == -1) { 1.108 + return -1; 1.109 + } 1.110 + if(psys_init_track(&pattr->alpha) == -1) { 1.111 + psys_destroy_track3(&pattr->color); 1.112 + return -1; 1.113 + } 1.114 + if(psys_init_track(&pattr->size) == -1) { 1.115 + psys_destroy_track3(&pattr->color); 1.116 + psys_destroy_track(&pattr->alpha); 1.117 + return -1; 1.118 + } 1.119 + 1.120 + anm_set_track_default(&pattr->color.x, 1.0); 1.121 + anm_set_track_default(&pattr->color.y, 1.0); 1.122 + anm_set_track_default(&pattr->color.z, 1.0); 1.123 + anm_set_track_default(&pattr->alpha.trk, 1.0); 1.124 + anm_set_track_default(&pattr->size.trk, 1.0); 1.125 + return 0; 1.126 +} 1.127 + 1.128 + 1.129 +void psys_destroy_attr(struct psys_attributes *attr) 1.130 +{ 1.131 + psys_destroy_track3(&attr->spawn_range); 1.132 + psys_destroy_track(&attr->rate); 1.133 + psys_destroy_anm_rnd(&attr->life); 1.134 + psys_destroy_anm_rnd(&attr->size); 1.135 + psys_destroy_anm_rnd3(&attr->dir); 1.136 + psys_destroy_track3(&attr->grav); 1.137 + 1.138 + destroy_particle_attr(&attr->part_attr); 1.139 + 1.140 + if(attr->tex && unload_texture) { 1.141 + unload_texture(attr->tex, tex_cls); 1.142 + } 1.143 +} 1.144 + 1.145 +static void destroy_particle_attr(struct psys_particle_attributes *pattr) 1.146 +{ 1.147 + psys_destroy_track3(&pattr->color); 1.148 + psys_destroy_track(&pattr->alpha); 1.149 + psys_destroy_track(&pattr->size); 1.150 +} 1.151 + 1.152 +void psys_eval_attr(struct psys_attributes *attr, anm_time_t tm) 1.153 +{ 1.154 + psys_eval_track3(&attr->spawn_range, tm); 1.155 + psys_eval_track(&attr->rate, tm); 1.156 + psys_eval_anm_rnd(&attr->life, tm); 1.157 + psys_eval_anm_rnd(&attr->size, tm); 1.158 + psys_eval_anm_rnd3(&attr->dir, tm); 1.159 + psys_eval_track3(&attr->grav, tm); 1.160 +} 1.161 + 1.162 +int psys_load_attr(struct psys_attributes *attr, const char *fname) 1.163 +{ 1.164 + FILE *fp; 1.165 + int res; 1.166 + 1.167 + if(!fname) { 1.168 + return -1; 1.169 + } 1.170 + 1.171 + if(!(fp = fopen(fname, "r"))) { 1.172 + fprintf(stderr, "%s: failed to read file: %s: %s\n", __func__, fname, strerror(errno)); 1.173 + return -1; 1.174 + } 1.175 + res = psys_load_attr_stream(attr, fp); 1.176 + fclose(fp); 1.177 + return res; 1.178 +} 1.179 + 1.180 +int psys_load_attr_stream(struct psys_attributes *attr, FILE *fp) 1.181 +{ 1.182 + int lineno = 0; 1.183 + char buf[512]; 1.184 + struct cfgopt *opt = 0; 1.185 + 1.186 + psys_init_attr(attr); 1.187 + 1.188 + while(fgets(buf, sizeof buf, fp)) { 1.189 + 1.190 + lineno++; 1.191 + 1.192 + if(!(opt = get_cfg_opt(buf))) { 1.193 + continue; 1.194 + } 1.195 + 1.196 + if(strcmp(opt->name, "texture") == 0) { 1.197 + if(opt->type != OPT_STR) { 1.198 + goto err; 1.199 + } 1.200 + if(!(attr->tex = load_texture(opt->valstr, tex_cls))) { 1.201 + fprintf(stderr, "failed to load texture: %s\n", opt->valstr); 1.202 + goto err; 1.203 + } 1.204 + 1.205 + release_cfg_opt(opt); 1.206 + continue; 1.207 + } else if(opt->type == OPT_STR) { 1.208 + fprintf(stderr, "invalid particle config: '%s'\n", opt->name); 1.209 + goto err; 1.210 + } 1.211 + 1.212 + if(strcmp(opt->name, "spawn_range") == 0) { 1.213 + psys_set_value3(&attr->spawn_range, opt->tm, opt->val); 1.214 + } else if(strcmp(opt->name, "rate") == 0) { 1.215 + psys_set_value(&attr->rate, opt->tm, opt->val.x); 1.216 + } else if(strcmp(opt->name, "life") == 0) { 1.217 + psys_set_anm_rnd(&attr->life, opt->tm, opt->val.x, opt->valrng.x); 1.218 + } else if(strcmp(opt->name, "size") == 0) { 1.219 + psys_set_anm_rnd(&attr->size, opt->tm, opt->val.x, opt->valrng.x); 1.220 + } else if(strcmp(opt->name, "dir") == 0) { 1.221 + psys_set_anm_rnd3(&attr->dir, opt->tm, opt->val, opt->valrng); 1.222 + } else if(strcmp(opt->name, "grav") == 0) { 1.223 + psys_set_value3(&attr->grav, opt->tm, opt->val); 1.224 + } else if(strcmp(opt->name, "drag") == 0) { 1.225 + attr->drag = opt->val.x; 1.226 + } else if(strcmp(opt->name, "pcolor") == 0) { 1.227 + psys_set_value3(&attr->part_attr.color, opt->tm, opt->val); 1.228 + } else if(strcmp(opt->name, "palpha") == 0) { 1.229 + psys_set_value(&attr->part_attr.alpha, opt->tm, opt->val.x); 1.230 + } else if(strcmp(opt->name, "psize") == 0) { 1.231 + psys_set_value(&attr->part_attr.size, opt->tm, opt->val.x); 1.232 + } else { 1.233 + fprintf(stderr, "unrecognized particle config option: %s\n", opt->name); 1.234 + goto err; 1.235 + } 1.236 + 1.237 + release_cfg_opt(opt); 1.238 + } 1.239 + 1.240 + return 0; 1.241 + 1.242 +err: 1.243 + fprintf(stderr, "Line %d: error parsing particle definition\n", lineno); 1.244 + release_cfg_opt(opt); 1.245 + return -1; 1.246 +} 1.247 + 1.248 +static struct cfgopt *get_cfg_opt(const char *line) 1.249 +{ 1.250 + char *buf, *tmp; 1.251 + struct cfgopt *opt; 1.252 + 1.253 + line = stripspace((char*)line); 1.254 + if(line[0] == '#' || !line[0]) { 1.255 + return 0; /* skip empty lines and comments */ 1.256 + } 1.257 + 1.258 + if(!(opt = malloc(sizeof *opt))) { 1.259 + return 0; 1.260 + } 1.261 + 1.262 + if(!(opt->valstr = strchr(line, '='))) { 1.263 + release_cfg_opt(opt); 1.264 + return 0; 1.265 + } 1.266 + *opt->valstr++ = 0; 1.267 + opt->valstr = stripspace(opt->valstr); 1.268 + 1.269 + /* allocate a working buffer on the stack that could fit the current line */ 1.270 + buf = alloca(strlen(line) + 1); 1.271 + strcpy(buf, line); 1.272 + buf = stripspace(buf); 1.273 + 1.274 + /* parse the keyframe time specifier if it exists */ 1.275 + if((tmp = strchr(buf, '('))) { 1.276 + char *endp; 1.277 + float tval; 1.278 + 1.279 + *tmp++ = 0; 1.280 + opt->name = strdup(buf); 1.281 + 1.282 + tval = strtod(tmp, &endp); 1.283 + if(endp == tmp) { /* nada ... */ 1.284 + opt->tm = 0; 1.285 + } else if(*endp == 's') { /* seconds suffix */ 1.286 + opt->tm = (long)(tval * 1000.0f); 1.287 + } else { 1.288 + opt->tm = (long)tval; 1.289 + } 1.290 + } else { 1.291 + opt->name = strdup(buf); 1.292 + opt->tm = 0; 1.293 + } 1.294 + 1.295 + if(sscanf(opt->valstr, "[%f %f %f] ~ [%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z, 1.296 + &opt->valrng.x, &opt->valrng.y, &opt->valrng.z) == 6) { 1.297 + /* value is a vector range */ 1.298 + opt->type = OPT_VEC_RANGE; 1.299 + 1.300 + } else if(sscanf(opt->valstr, "%f ~ %f", &opt->val.x, &opt->valrng.x) == 2) { 1.301 + /* value is a number range */ 1.302 + opt->type = OPT_NUM_RANGE; 1.303 + opt->val.y = opt->val.z = opt->val.x; 1.304 + opt->valrng.y = opt->valrng.z = opt->valrng.x; 1.305 + 1.306 + } else if(sscanf(opt->valstr, "[%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z) == 3) { 1.307 + /* value is a vector */ 1.308 + opt->type = OPT_VEC; 1.309 + opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f; 1.310 + 1.311 + } else if(sscanf(opt->valstr, "%f", &opt->val.x) == 1) { 1.312 + /* value is a number */ 1.313 + opt->type = OPT_NUM; 1.314 + opt->val.y = opt->val.z = opt->val.x; 1.315 + opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f; 1.316 + 1.317 + } else if(sscanf(opt->valstr, "\"%s\"", buf) == 1) { 1.318 + /* just a string... strip the quotes */ 1.319 + if(buf[strlen(buf) - 1] == '\"') { 1.320 + buf[strlen(buf) - 1] = 0; 1.321 + } 1.322 + opt->type = OPT_STR; 1.323 + opt->valstr = strdup(buf); 1.324 + } else { 1.325 + /* fuck it ... */ 1.326 + release_cfg_opt(opt); 1.327 + return 0; 1.328 + } 1.329 + 1.330 + return opt; 1.331 +} 1.332 + 1.333 +static void release_cfg_opt(struct cfgopt *opt) 1.334 +{ 1.335 + if(opt) { 1.336 + free(opt->name); 1.337 + } 1.338 +} 1.339 + 1.340 + 1.341 +int psys_save_attr(struct psys_attributes *attr, const char *fname) 1.342 +{ 1.343 + FILE *fp; 1.344 + int res; 1.345 + 1.346 + if(!(fp = fopen(fname, "w"))) { 1.347 + fprintf(stderr, "%s: failed to write file: %s: %s\n", __func__, fname, strerror(errno)); 1.348 + return -1; 1.349 + } 1.350 + res = psys_save_attr_stream(attr, fp); 1.351 + fclose(fp); 1.352 + return res; 1.353 +} 1.354 + 1.355 +int psys_save_attr_stream(struct psys_attributes *attr, FILE *fp) 1.356 +{ 1.357 + return -1; /* TODO */ 1.358 +} 1.359 + 1.360 + 1.361 +static char *stripspace(char *str) 1.362 +{ 1.363 + char *end; 1.364 + 1.365 + while(*str && isspace(*str)) { 1.366 + str++; 1.367 + } 1.368 + 1.369 + end = str + strlen(str) - 1; 1.370 + while(end >= str && isspace(*end)) { 1.371 + *end-- = 0; 1.372 + } 1.373 + return str; 1.374 +}