libpsys

annotate src/pattr.c @ 15:5678915dc2c7

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