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 }
|