libpsys

view src/pattr.c @ 16:3871a45a4e4b

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