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