libpsys

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