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