dungeon_crawler

annotate prototype/psys/pattr.c @ 80:a373b36ffc17

better
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Oct 2012 01:59:39 +0300
parents 2560a7ab0243
children
rev   line source
nuclear@67 1 #define _GNU_SOURCE
nuclear@67 2 #include <stdio.h>
nuclear@67 3 #include <stdlib.h>
nuclear@67 4 #include <string.h>
nuclear@67 5 #include <errno.h>
nuclear@67 6 #include <ctype.h>
nuclear@67 7
nuclear@67 8 #ifdef _MSC_VER
nuclear@67 9 #include <malloc.h>
nuclear@67 10 #else
nuclear@67 11 #include <alloca.h>
nuclear@67 12 #endif
nuclear@67 13
nuclear@67 14 #include "pattr.h"
nuclear@67 15 #include "psys_gl.h"
nuclear@67 16
nuclear@67 17 enum {
nuclear@67 18 OPT_STR,
nuclear@67 19 OPT_NUM,
nuclear@67 20 OPT_NUM_RANGE,
nuclear@67 21 OPT_VEC,
nuclear@67 22 OPT_VEC_RANGE
nuclear@67 23 };
nuclear@67 24
nuclear@67 25 struct cfgopt {
nuclear@67 26 char *name;
nuclear@67 27 int type;
nuclear@67 28 long tm;
nuclear@67 29 char *valstr;
nuclear@67 30 vec3_t val, valrng;
nuclear@67 31 };
nuclear@67 32
nuclear@67 33 static int init_particle_attr(struct psys_particle_attributes *pattr);
nuclear@67 34 static void destroy_particle_attr(struct psys_particle_attributes *pattr);
nuclear@67 35 static struct cfgopt *get_cfg_opt(const char *line);
nuclear@67 36 static void release_cfg_opt(struct cfgopt *opt);
nuclear@67 37 static char *stripspace(char *str);
nuclear@67 38
nuclear@67 39 static void *tex_cls;
nuclear@67 40 static unsigned int (*load_texture)(const char*, void*) = psys_gl_load_texture;
nuclear@67 41 static void (*unload_texture)(unsigned int, void*) = psys_gl_unload_texture;
nuclear@67 42
nuclear@67 43
nuclear@67 44 void psys_texture_loader(unsigned int (*load)(const char*, void*), void (*unload)(unsigned int, void*), void *cls)
nuclear@67 45 {
nuclear@67 46 load_texture = load;
nuclear@67 47 unload_texture = unload;
nuclear@67 48 tex_cls = cls;
nuclear@67 49 }
nuclear@67 50
nuclear@67 51 struct psys_attributes *psys_create_attr(void)
nuclear@67 52 {
nuclear@67 53 struct psys_attributes *attr = malloc(sizeof *attr);
nuclear@67 54 if(attr) {
nuclear@67 55 if(psys_init_attr(attr) == -1) {
nuclear@67 56 free(attr);
nuclear@67 57 attr = 0;
nuclear@67 58 }
nuclear@67 59 }
nuclear@67 60 return attr;
nuclear@67 61 }
nuclear@67 62
nuclear@67 63 void psys_free_attr(struct psys_attributes *attr)
nuclear@67 64 {
nuclear@67 65 psys_destroy_attr(attr);
nuclear@67 66 free(attr);
nuclear@67 67 }
nuclear@67 68
nuclear@67 69 int psys_init_attr(struct psys_attributes *attr)
nuclear@67 70 {
nuclear@67 71 memset(attr, 0, sizeof *attr);
nuclear@67 72
nuclear@67 73 if(psys_init_track3(&attr->spawn_range) == -1)
nuclear@67 74 goto err;
nuclear@67 75 if(psys_init_track(&attr->rate) == -1)
nuclear@67 76 goto err;
nuclear@67 77 if(psys_init_anm_rnd(&attr->life) == -1)
nuclear@67 78 goto err;
nuclear@67 79 if(psys_init_anm_rnd(&attr->size) == -1)
nuclear@67 80 goto err;
nuclear@67 81 if(psys_init_anm_rnd3(&attr->dir) == -1)
nuclear@67 82 goto err;
nuclear@67 83 if(psys_init_track3(&attr->grav) == -1)
nuclear@67 84 goto err;
nuclear@67 85
nuclear@67 86 if(init_particle_attr(&attr->part_attr) == -1)
nuclear@67 87 goto err;
nuclear@67 88
nuclear@67 89 attr->max_particles = -1;
nuclear@67 90
nuclear@67 91 anm_set_track_default(&attr->size.value.trk, 1.0);
nuclear@67 92 anm_set_track_default(&attr->life.value.trk, 1.0);
nuclear@67 93
nuclear@67 94 return 0;
nuclear@67 95
nuclear@67 96 err:
nuclear@67 97 psys_destroy_attr(attr);
nuclear@67 98 return -1;
nuclear@67 99 }
nuclear@67 100
nuclear@67 101
nuclear@67 102 static int init_particle_attr(struct psys_particle_attributes *pattr)
nuclear@67 103 {
nuclear@67 104 if(psys_init_track3(&pattr->color) == -1) {
nuclear@67 105 return -1;
nuclear@67 106 }
nuclear@67 107 if(psys_init_track(&pattr->alpha) == -1) {
nuclear@67 108 psys_destroy_track3(&pattr->color);
nuclear@67 109 return -1;
nuclear@67 110 }
nuclear@67 111 if(psys_init_track(&pattr->size) == -1) {
nuclear@67 112 psys_destroy_track3(&pattr->color);
nuclear@67 113 psys_destroy_track(&pattr->alpha);
nuclear@67 114 return -1;
nuclear@67 115 }
nuclear@67 116
nuclear@67 117 anm_set_track_default(&pattr->color.x, 1.0);
nuclear@67 118 anm_set_track_default(&pattr->color.y, 1.0);
nuclear@67 119 anm_set_track_default(&pattr->color.z, 1.0);
nuclear@67 120 anm_set_track_default(&pattr->alpha.trk, 1.0);
nuclear@67 121 anm_set_track_default(&pattr->size.trk, 1.0);
nuclear@67 122 return 0;
nuclear@67 123 }
nuclear@67 124
nuclear@67 125
nuclear@67 126 void psys_destroy_attr(struct psys_attributes *attr)
nuclear@67 127 {
nuclear@67 128 psys_destroy_track3(&attr->spawn_range);
nuclear@67 129 psys_destroy_track(&attr->rate);
nuclear@67 130 psys_destroy_anm_rnd(&attr->life);
nuclear@67 131 psys_destroy_anm_rnd(&attr->size);
nuclear@67 132 psys_destroy_anm_rnd3(&attr->dir);
nuclear@67 133 psys_destroy_track3(&attr->grav);
nuclear@67 134
nuclear@67 135 destroy_particle_attr(&attr->part_attr);
nuclear@67 136
nuclear@67 137 if(attr->tex && unload_texture) {
nuclear@67 138 unload_texture(attr->tex, tex_cls);
nuclear@67 139 }
nuclear@67 140 }
nuclear@67 141
nuclear@67 142 static void destroy_particle_attr(struct psys_particle_attributes *pattr)
nuclear@67 143 {
nuclear@67 144 psys_destroy_track3(&pattr->color);
nuclear@67 145 psys_destroy_track(&pattr->alpha);
nuclear@67 146 psys_destroy_track(&pattr->size);
nuclear@67 147 }
nuclear@67 148
nuclear@67 149 void psys_eval_attr(struct psys_attributes *attr, anm_time_t tm)
nuclear@67 150 {
nuclear@67 151 psys_eval_track3(&attr->spawn_range, tm);
nuclear@67 152 psys_eval_track(&attr->rate, tm);
nuclear@67 153 psys_eval_anm_rnd(&attr->life, tm);
nuclear@67 154 psys_eval_anm_rnd(&attr->size, tm);
nuclear@67 155 psys_eval_anm_rnd3(&attr->dir, tm);
nuclear@67 156 psys_eval_track3(&attr->grav, tm);
nuclear@67 157 }
nuclear@67 158
nuclear@67 159 int psys_load_attr(struct psys_attributes *attr, const char *fname)
nuclear@67 160 {
nuclear@67 161 FILE *fp;
nuclear@67 162 int res;
nuclear@67 163
nuclear@67 164 if(!fname) {
nuclear@67 165 return -1;
nuclear@67 166 }
nuclear@67 167
nuclear@67 168 if(!(fp = fopen(fname, "r"))) {
nuclear@69 169 fprintf(stderr, "%s: failed to read file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
nuclear@67 170 return -1;
nuclear@67 171 }
nuclear@67 172 res = psys_load_attr_stream(attr, fp);
nuclear@67 173 fclose(fp);
nuclear@67 174 return res;
nuclear@67 175 }
nuclear@67 176
nuclear@67 177 int psys_load_attr_stream(struct psys_attributes *attr, FILE *fp)
nuclear@67 178 {
nuclear@67 179 int lineno = 0;
nuclear@67 180 char buf[512];
nuclear@67 181 struct cfgopt *opt = 0;
nuclear@67 182
nuclear@67 183 psys_init_attr(attr);
nuclear@67 184
nuclear@67 185 while(fgets(buf, sizeof buf, fp)) {
nuclear@67 186
nuclear@67 187 lineno++;
nuclear@67 188
nuclear@67 189 if(!(opt = get_cfg_opt(buf))) {
nuclear@67 190 continue;
nuclear@67 191 }
nuclear@67 192
nuclear@67 193 if(strcmp(opt->name, "texture") == 0) {
nuclear@67 194 if(opt->type != OPT_STR) {
nuclear@67 195 goto err;
nuclear@67 196 }
nuclear@67 197 if(!(attr->tex = load_texture(opt->valstr, tex_cls))) {
nuclear@67 198 fprintf(stderr, "failed to load texture: %s\n", opt->valstr);
nuclear@67 199 goto err;
nuclear@67 200 }
nuclear@67 201
nuclear@67 202 release_cfg_opt(opt);
nuclear@67 203 continue;
nuclear@67 204 } else if(opt->type == OPT_STR) {
nuclear@67 205 fprintf(stderr, "invalid particle config: '%s'\n", opt->name);
nuclear@67 206 goto err;
nuclear@67 207 }
nuclear@67 208
nuclear@67 209 if(strcmp(opt->name, "spawn_range") == 0) {
nuclear@67 210 psys_set_value3(&attr->spawn_range, opt->tm, opt->val);
nuclear@67 211 } else if(strcmp(opt->name, "rate") == 0) {
nuclear@67 212 psys_set_value(&attr->rate, opt->tm, opt->val.x);
nuclear@67 213 } else if(strcmp(opt->name, "life") == 0) {
nuclear@67 214 psys_set_anm_rnd(&attr->life, opt->tm, opt->val.x, opt->valrng.x);
nuclear@67 215 } else if(strcmp(opt->name, "size") == 0) {
nuclear@67 216 psys_set_anm_rnd(&attr->size, opt->tm, opt->val.x, opt->valrng.x);
nuclear@67 217 } else if(strcmp(opt->name, "dir") == 0) {
nuclear@67 218 psys_set_anm_rnd3(&attr->dir, opt->tm, opt->val, opt->valrng);
nuclear@67 219 } else if(strcmp(opt->name, "grav") == 0) {
nuclear@67 220 psys_set_value3(&attr->grav, opt->tm, opt->val);
nuclear@67 221 } else if(strcmp(opt->name, "drag") == 0) {
nuclear@67 222 attr->drag = opt->val.x;
nuclear@67 223 } else if(strcmp(opt->name, "pcolor") == 0) {
nuclear@67 224 psys_set_value3(&attr->part_attr.color, opt->tm, opt->val);
nuclear@67 225 } else if(strcmp(opt->name, "palpha") == 0) {
nuclear@67 226 psys_set_value(&attr->part_attr.alpha, opt->tm, opt->val.x);
nuclear@67 227 } else if(strcmp(opt->name, "psize") == 0) {
nuclear@67 228 psys_set_value(&attr->part_attr.size, opt->tm, opt->val.x);
nuclear@67 229 } else {
nuclear@67 230 fprintf(stderr, "unrecognized particle config option: %s\n", opt->name);
nuclear@67 231 goto err;
nuclear@67 232 }
nuclear@67 233
nuclear@67 234 release_cfg_opt(opt);
nuclear@67 235 }
nuclear@67 236
nuclear@67 237 return 0;
nuclear@67 238
nuclear@67 239 err:
nuclear@67 240 fprintf(stderr, "Line %d: error parsing particle definition\n", lineno);
nuclear@67 241 release_cfg_opt(opt);
nuclear@67 242 return -1;
nuclear@67 243 }
nuclear@67 244
nuclear@67 245 static struct cfgopt *get_cfg_opt(const char *line)
nuclear@67 246 {
nuclear@67 247 char *buf, *tmp;
nuclear@67 248 struct cfgopt *opt;
nuclear@67 249
nuclear@69 250 /* allocate a working buffer on the stack that could fit the current line */
nuclear@69 251 buf = alloca(strlen(line) + 1);
nuclear@69 252
nuclear@67 253 line = stripspace((char*)line);
nuclear@67 254 if(line[0] == '#' || !line[0]) {
nuclear@67 255 return 0; /* skip empty lines and comments */
nuclear@67 256 }
nuclear@67 257
nuclear@67 258 if(!(opt = malloc(sizeof *opt))) {
nuclear@67 259 return 0;
nuclear@67 260 }
nuclear@67 261
nuclear@67 262 if(!(opt->valstr = strchr(line, '='))) {
nuclear@67 263 release_cfg_opt(opt);
nuclear@67 264 return 0;
nuclear@67 265 }
nuclear@67 266 *opt->valstr++ = 0;
nuclear@67 267 opt->valstr = stripspace(opt->valstr);
nuclear@67 268
nuclear@67 269 strcpy(buf, line);
nuclear@67 270 buf = stripspace(buf);
nuclear@67 271
nuclear@67 272 /* parse the keyframe time specifier if it exists */
nuclear@67 273 if((tmp = strchr(buf, '('))) {
nuclear@67 274 char *endp;
nuclear@67 275 float tval;
nuclear@67 276
nuclear@67 277 *tmp++ = 0;
nuclear@69 278 opt->name = malloc(strlen(buf) + 1);
nuclear@69 279 strcpy(opt->name, buf);
nuclear@67 280
nuclear@67 281 tval = strtod(tmp, &endp);
nuclear@67 282 if(endp == tmp) { /* nada ... */
nuclear@67 283 opt->tm = 0;
nuclear@67 284 } else if(*endp == 's') { /* seconds suffix */
nuclear@67 285 opt->tm = (long)(tval * 1000.0f);
nuclear@67 286 } else {
nuclear@67 287 opt->tm = (long)tval;
nuclear@67 288 }
nuclear@67 289 } else {
nuclear@69 290 opt->name = malloc(strlen(buf) + 1);
nuclear@69 291 strcpy(opt->name, buf);
nuclear@67 292 opt->tm = 0;
nuclear@67 293 }
nuclear@67 294
nuclear@67 295 if(sscanf(opt->valstr, "[%f %f %f] ~ [%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z,
nuclear@67 296 &opt->valrng.x, &opt->valrng.y, &opt->valrng.z) == 6) {
nuclear@67 297 /* value is a vector range */
nuclear@67 298 opt->type = OPT_VEC_RANGE;
nuclear@67 299
nuclear@67 300 } else if(sscanf(opt->valstr, "%f ~ %f", &opt->val.x, &opt->valrng.x) == 2) {
nuclear@67 301 /* value is a number range */
nuclear@67 302 opt->type = OPT_NUM_RANGE;
nuclear@67 303 opt->val.y = opt->val.z = opt->val.x;
nuclear@67 304 opt->valrng.y = opt->valrng.z = opt->valrng.x;
nuclear@67 305
nuclear@67 306 } else if(sscanf(opt->valstr, "[%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z) == 3) {
nuclear@67 307 /* value is a vector */
nuclear@67 308 opt->type = OPT_VEC;
nuclear@67 309 opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f;
nuclear@67 310
nuclear@67 311 } else if(sscanf(opt->valstr, "%f", &opt->val.x) == 1) {
nuclear@67 312 /* value is a number */
nuclear@67 313 opt->type = OPT_NUM;
nuclear@67 314 opt->val.y = opt->val.z = opt->val.x;
nuclear@67 315 opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f;
nuclear@67 316
nuclear@67 317 } else if(sscanf(opt->valstr, "\"%s\"", buf) == 1) {
nuclear@67 318 /* just a string... strip the quotes */
nuclear@67 319 if(buf[strlen(buf) - 1] == '\"') {
nuclear@67 320 buf[strlen(buf) - 1] = 0;
nuclear@67 321 }
nuclear@67 322 opt->type = OPT_STR;
nuclear@67 323 opt->valstr = strdup(buf);
nuclear@67 324 } else {
nuclear@67 325 /* fuck it ... */
nuclear@67 326 release_cfg_opt(opt);
nuclear@67 327 return 0;
nuclear@67 328 }
nuclear@67 329
nuclear@67 330 return opt;
nuclear@67 331 }
nuclear@67 332
nuclear@67 333 static void release_cfg_opt(struct cfgopt *opt)
nuclear@67 334 {
nuclear@67 335 if(opt) {
nuclear@67 336 free(opt->name);
nuclear@69 337 opt->name = 0;
nuclear@67 338 }
nuclear@69 339 opt = 0;
nuclear@67 340 }
nuclear@67 341
nuclear@67 342
nuclear@67 343 int psys_save_attr(struct psys_attributes *attr, const char *fname)
nuclear@67 344 {
nuclear@67 345 FILE *fp;
nuclear@67 346 int res;
nuclear@67 347
nuclear@67 348 if(!(fp = fopen(fname, "w"))) {
nuclear@69 349 fprintf(stderr, "%s: failed to write file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
nuclear@67 350 return -1;
nuclear@67 351 }
nuclear@67 352 res = psys_save_attr_stream(attr, fp);
nuclear@67 353 fclose(fp);
nuclear@67 354 return res;
nuclear@67 355 }
nuclear@67 356
nuclear@67 357 int psys_save_attr_stream(struct psys_attributes *attr, FILE *fp)
nuclear@67 358 {
nuclear@67 359 return -1; /* TODO */
nuclear@67 360 }
nuclear@67 361
nuclear@67 362
nuclear@67 363 static char *stripspace(char *str)
nuclear@67 364 {
nuclear@67 365 char *end;
nuclear@67 366
nuclear@67 367 while(*str && isspace(*str)) {
nuclear@67 368 str++;
nuclear@67 369 }
nuclear@67 370
nuclear@67 371 end = str + strlen(str) - 1;
nuclear@67 372 while(end >= str && isspace(*end)) {
nuclear@67 373 *end-- = 0;
nuclear@67 374 }
nuclear@67 375 return str;
nuclear@67 376 }