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