libpsys

annotate src/pattr.c @ 17:7fbed016e739

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