libpsys

annotate src/pattr.c @ 20:0a53b22f7caf

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