rev |
line source |
nuclear@23
|
1 #include <stdio.h>
|
nuclear@23
|
2 #include <stdlib.h>
|
nuclear@23
|
3 #include <string.h>
|
nuclear@23
|
4 #include <errno.h>
|
nuclear@23
|
5 #include <ctype.h>
|
nuclear@23
|
6 #include <limits.h>
|
nuclear@23
|
7 #include <string>
|
nuclear@23
|
8 #include <vector>
|
nuclear@23
|
9 #include <map>
|
nuclear@23
|
10 #include "scene.h"
|
nuclear@23
|
11 #include "vector.h"
|
nuclear@23
|
12
|
nuclear@23
|
13 #ifndef PATH_MAX
|
nuclear@23
|
14 #define PATH_MAX 512
|
nuclear@23
|
15 #endif
|
nuclear@23
|
16
|
nuclear@23
|
17 #define COMMANDS \
|
nuclear@23
|
18 CMD(V), \
|
nuclear@23
|
19 CMD(VN), \
|
nuclear@23
|
20 CMD(VT), \
|
nuclear@23
|
21 CMD(F), \
|
nuclear@23
|
22 CMD(O), \
|
nuclear@23
|
23 CMD(G), \
|
nuclear@23
|
24 CMD(MTLLIB), \
|
nuclear@23
|
25 CMD(USEMTL), \
|
nuclear@23
|
26 CMD(NEWMTL), \
|
nuclear@23
|
27 CMD(KA), \
|
nuclear@23
|
28 CMD(KD), \
|
nuclear@23
|
29 CMD(KS), \
|
nuclear@23
|
30 CMD(KR), \
|
nuclear@23
|
31 CMD(NS), \
|
nuclear@23
|
32 CMD(NI), \
|
nuclear@23
|
33 CMD(D), \
|
nuclear@23
|
34 CMD(TR), \
|
nuclear@23
|
35 CMD(MAP_KD), \
|
nuclear@23
|
36 CMD(MAP_KS), \
|
nuclear@23
|
37 CMD(MAP_NS), \
|
nuclear@23
|
38 CMD(MAP_D), \
|
nuclear@23
|
39 CMD(REFL), \
|
nuclear@23
|
40 CMD(BUMP)
|
nuclear@23
|
41
|
nuclear@23
|
42 #define CMD(x) CMD_##x
|
nuclear@23
|
43 enum {
|
nuclear@23
|
44 COMMANDS,
|
nuclear@23
|
45 CMD_UNK
|
nuclear@23
|
46 };
|
nuclear@23
|
47 #undef CMD
|
nuclear@23
|
48
|
nuclear@23
|
49 #define CMD(x) #x
|
nuclear@23
|
50 static const char *cmd_names[] = {
|
nuclear@23
|
51 COMMANDS,
|
nuclear@23
|
52 0
|
nuclear@23
|
53 };
|
nuclear@23
|
54 #undef CMD
|
nuclear@23
|
55
|
nuclear@23
|
56 struct obj_face {
|
nuclear@23
|
57 int elem;
|
nuclear@23
|
58 int v[4], n[4], t[4];
|
nuclear@23
|
59 };
|
nuclear@23
|
60
|
nuclear@23
|
61 struct obj_file {
|
nuclear@23
|
62 std::string cur_obj, cur_mat;
|
nuclear@23
|
63 std::vector<Vector3> v, vn, vt;
|
nuclear@23
|
64 std::vector<obj_face> f;
|
nuclear@23
|
65 };
|
nuclear@23
|
66
|
nuclear@23
|
67 struct obj_mat {
|
nuclear@23
|
68 std::string name; // newmtl <name>
|
nuclear@23
|
69 Vector3 ambient, diffuse, specular; // Ka, Kd, Ks
|
nuclear@23
|
70 float shininess; // Ns
|
nuclear@23
|
71 float ior; // Ni
|
nuclear@23
|
72 float alpha; // d, Tr
|
nuclear@23
|
73 float refl; // Kr (my extesnsion)
|
nuclear@23
|
74
|
nuclear@23
|
75 std::string tex_dif, tex_spec, tex_shin, tex_alpha; // map_Kd, map_Ks, map_Ns, map_d
|
nuclear@23
|
76 std::string tex_refl; // refl -type sphere|cube file
|
nuclear@23
|
77 std::string tex_bump; // bump
|
nuclear@23
|
78
|
nuclear@23
|
79 obj_mat() { reset(); }
|
nuclear@23
|
80
|
nuclear@23
|
81 void reset() {
|
nuclear@23
|
82 ambient = diffuse = Vector3(0.5, 0.5, 0.5);
|
nuclear@23
|
83 specular = Vector3(0.0, 0.0, 0.0);
|
nuclear@23
|
84 name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = "";
|
nuclear@23
|
85 shininess = 0;
|
nuclear@23
|
86 ior = alpha = 1;
|
nuclear@23
|
87 refl = 0.0;
|
nuclear@23
|
88 }
|
nuclear@23
|
89 };
|
nuclear@23
|
90
|
nuclear@23
|
91 static bool read_materials(FILE *fp, std::vector<obj_mat> *vmtl);
|
nuclear@23
|
92 static Mesh *cons_mesh(obj_file *obj);
|
nuclear@23
|
93
|
nuclear@23
|
94 static int get_cmd(char *str);
|
nuclear@23
|
95 static bool is_int(const char *str);
|
nuclear@23
|
96 static bool is_float(const char *str);
|
nuclear@23
|
97 static bool parse_vec(Vector3 *vec);
|
nuclear@23
|
98 static bool parse_color(Vector3 *col);
|
nuclear@23
|
99 static bool parse_face(obj_face *face);
|
nuclear@23
|
100 static const char *parse_map();
|
nuclear@23
|
101
|
nuclear@23
|
102 static bool find_file(char *res, int sz, const char *fname, const char *path = ".", const char *mode = "rb");
|
nuclear@23
|
103 static const char *dirname(const char *str);
|
nuclear@23
|
104
|
nuclear@23
|
105 static std::map<std::string, int> matnames;
|
nuclear@23
|
106
|
nuclear@23
|
107 #define INVALID_IDX INT_MIN
|
nuclear@23
|
108
|
nuclear@23
|
109 #define SEP " \t\n\r\v"
|
nuclear@23
|
110 #define BUF_SZ 512
|
nuclear@23
|
111
|
nuclear@23
|
112
|
nuclear@23
|
113 bool Scene::load(const char *fname)
|
nuclear@23
|
114 {
|
nuclear@23
|
115 FILE *fp;
|
nuclear@23
|
116
|
nuclear@23
|
117 if(!(fp = fopen(fname, "rb"))) {
|
nuclear@23
|
118 fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno));
|
nuclear@23
|
119 return false;
|
nuclear@23
|
120 }
|
nuclear@23
|
121
|
nuclear@23
|
122 bool res = load(fp);
|
nuclear@23
|
123 fclose(fp);
|
nuclear@23
|
124 return res;
|
nuclear@23
|
125 }
|
nuclear@23
|
126
|
nuclear@23
|
127 bool Scene::load(FILE *fp)
|
nuclear@23
|
128 {
|
nuclear@23
|
129 static int seq;
|
nuclear@23
|
130 char cur_name[16];
|
nuclear@23
|
131
|
nuclear@23
|
132 obj_file obj;
|
nuclear@23
|
133
|
nuclear@23
|
134 sprintf(cur_name, "default%02d.obj", seq++);
|
nuclear@23
|
135 obj.cur_obj = cur_name;
|
nuclear@23
|
136
|
nuclear@23
|
137 int prev_cmd = 0, obj_added = 0;
|
nuclear@23
|
138 for(;;) {
|
nuclear@23
|
139 Vector3 vec;
|
nuclear@23
|
140 obj_face face;
|
nuclear@23
|
141
|
nuclear@23
|
142 char line[BUF_SZ];
|
nuclear@23
|
143 fgets(line, sizeof line, fp);
|
nuclear@23
|
144 if(feof(fp)) {
|
nuclear@23
|
145 break;
|
nuclear@23
|
146 }
|
nuclear@23
|
147
|
nuclear@23
|
148 char *tok;
|
nuclear@23
|
149 if(!(tok = strtok(line, SEP))) {
|
nuclear@23
|
150 continue; // ignore empty lines
|
nuclear@23
|
151 }
|
nuclear@23
|
152
|
nuclear@23
|
153 int cmd;
|
nuclear@23
|
154 if((cmd = get_cmd(tok)) == -1) {
|
nuclear@23
|
155 continue; // ignore unknown commands ...
|
nuclear@23
|
156 }
|
nuclear@23
|
157
|
nuclear@23
|
158 switch(cmd) {
|
nuclear@23
|
159 case CMD_V:
|
nuclear@23
|
160 if(!parse_vec(&vec)) {
|
nuclear@23
|
161 continue;
|
nuclear@23
|
162 }
|
nuclear@23
|
163 obj.v.push_back(vec);
|
nuclear@23
|
164 break;
|
nuclear@23
|
165
|
nuclear@23
|
166 case CMD_VN:
|
nuclear@23
|
167 if(!parse_vec(&vec)) {
|
nuclear@23
|
168 continue;
|
nuclear@23
|
169 }
|
nuclear@23
|
170 obj.vn.push_back(vec);
|
nuclear@23
|
171 break;
|
nuclear@23
|
172
|
nuclear@23
|
173 case CMD_VT:
|
nuclear@23
|
174 if(!parse_vec(&vec)) {
|
nuclear@23
|
175 continue;
|
nuclear@23
|
176 }
|
nuclear@23
|
177 vec.y = 1.0 - vec.y;
|
nuclear@23
|
178 obj.vt.push_back(vec);
|
nuclear@23
|
179 break;
|
nuclear@23
|
180
|
nuclear@23
|
181 case CMD_O:
|
nuclear@23
|
182 case CMD_G:
|
nuclear@23
|
183 if(prev_cmd == CMD_O || prev_cmd == CMD_G) {
|
nuclear@23
|
184 break; // just in case we've got both of them in a row
|
nuclear@23
|
185 }
|
nuclear@23
|
186 /* if we have any previous data, group them up, add the object
|
nuclear@23
|
187 * and continue with the new one...
|
nuclear@23
|
188 */
|
nuclear@23
|
189 if(!obj.f.empty()) {
|
nuclear@23
|
190 Mesh *mesh = cons_mesh(&obj);
|
nuclear@23
|
191 mesh->matid = matnames[obj.cur_mat];
|
nuclear@23
|
192 add_mesh(mesh);
|
nuclear@23
|
193 obj_added++;
|
nuclear@23
|
194
|
nuclear@23
|
195 obj.f.clear(); // clean the face list
|
nuclear@23
|
196 }
|
nuclear@23
|
197 if((tok = strtok(0, SEP))) {
|
nuclear@23
|
198 obj.cur_obj = tok;
|
nuclear@23
|
199 } else {
|
nuclear@23
|
200 sprintf(cur_name, "default%02d.obj", seq++);
|
nuclear@23
|
201 obj.cur_obj = cur_name;
|
nuclear@23
|
202 }
|
nuclear@23
|
203 break;
|
nuclear@23
|
204
|
nuclear@23
|
205 case CMD_MTLLIB:
|
nuclear@23
|
206 if((tok = strtok(0, SEP))) {
|
nuclear@23
|
207 char path[PATH_MAX];
|
nuclear@23
|
208
|
nuclear@23
|
209 sprintf(path, ".:%s", dirname(tok));
|
nuclear@23
|
210 if(!find_file(path, PATH_MAX, tok, path)) {
|
nuclear@23
|
211 fprintf(stderr, "material library not found: %s\n", tok);
|
nuclear@23
|
212 continue;
|
nuclear@23
|
213 }
|
nuclear@23
|
214
|
nuclear@23
|
215 FILE *mfile;
|
nuclear@23
|
216 if(!(mfile = fopen(path, "rb"))) {
|
nuclear@23
|
217 fprintf(stderr, "failed to open material library: %s\n", path);
|
nuclear@23
|
218 continue;
|
nuclear@23
|
219 }
|
nuclear@23
|
220
|
nuclear@23
|
221 // load all materials of the mtl file into a vector
|
nuclear@23
|
222 std::vector<obj_mat> vmtl;
|
nuclear@23
|
223 if(!read_materials(mfile, &vmtl)) {
|
nuclear@23
|
224 continue;
|
nuclear@23
|
225 }
|
nuclear@23
|
226 fclose(mfile);
|
nuclear@23
|
227
|
nuclear@23
|
228 // and add them all to the scene
|
nuclear@23
|
229 for(size_t i=0; i<vmtl.size(); i++) {
|
nuclear@23
|
230 Material mat;
|
nuclear@23
|
231
|
nuclear@23
|
232 mat.kd[0] = vmtl[i].diffuse.x;
|
nuclear@23
|
233 mat.kd[1] = vmtl[i].diffuse.y;
|
nuclear@23
|
234 mat.kd[2] = vmtl[i].diffuse.z;
|
nuclear@23
|
235
|
nuclear@23
|
236 mat.ks[0] = vmtl[i].specular.x;
|
nuclear@23
|
237 mat.ks[1] = vmtl[i].specular.y;
|
nuclear@23
|
238 mat.ks[2] = vmtl[i].specular.z;
|
nuclear@23
|
239
|
nuclear@23
|
240 mat.kt = 1.0 - vmtl[i].alpha;
|
nuclear@23
|
241 mat.kr = vmtl[i].refl;
|
nuclear@23
|
242 mat.spow = vmtl[i].shininess;
|
nuclear@23
|
243
|
nuclear@23
|
244 matlib.push_back(mat);
|
nuclear@23
|
245 matnames[vmtl[i].name] = i;
|
nuclear@23
|
246 }
|
nuclear@23
|
247 }
|
nuclear@23
|
248 break;
|
nuclear@23
|
249
|
nuclear@23
|
250 case CMD_USEMTL:
|
nuclear@23
|
251 if((tok = strtok(0, SEP))) {
|
nuclear@23
|
252 obj.cur_mat = tok;
|
nuclear@23
|
253 } else {
|
nuclear@23
|
254 obj.cur_mat = "";
|
nuclear@23
|
255 }
|
nuclear@23
|
256 break;
|
nuclear@23
|
257
|
nuclear@23
|
258 case CMD_F:
|
nuclear@23
|
259 if(!parse_face(&face)) {
|
nuclear@23
|
260 continue;
|
nuclear@23
|
261 }
|
nuclear@23
|
262
|
nuclear@23
|
263 // convert negative indices to regular indices
|
nuclear@23
|
264 for(int i=0; i<4; i++) {
|
nuclear@23
|
265 if(face.v[i] < 0 && face.v[i] != INVALID_IDX) {
|
nuclear@23
|
266 face.v[i] = obj.v.size() + face.v[i];
|
nuclear@23
|
267 }
|
nuclear@23
|
268 if(face.n[i] < 0 && face.n[i] != INVALID_IDX) {
|
nuclear@23
|
269 face.n[i] = obj.vn.size() + face.n[i];
|
nuclear@23
|
270 }
|
nuclear@23
|
271 if(face.t[i] < 0 && face.t[i] != INVALID_IDX) {
|
nuclear@23
|
272 face.t[i] = obj.vt.size() + face.t[i];
|
nuclear@23
|
273 }
|
nuclear@23
|
274 }
|
nuclear@23
|
275
|
nuclear@23
|
276 // break quads into triangles if needed
|
nuclear@23
|
277 obj.f.push_back(face);
|
nuclear@23
|
278 if(face.elem == 4) {
|
nuclear@23
|
279 face.v[1] = face.v[2];
|
nuclear@23
|
280 face.n[1] = face.n[2];
|
nuclear@23
|
281 face.t[1] = face.t[2];
|
nuclear@23
|
282
|
nuclear@23
|
283 face.v[2] = face.v[3];
|
nuclear@23
|
284 face.n[2] = face.n[3];
|
nuclear@23
|
285 face.t[2] = face.t[3];
|
nuclear@23
|
286
|
nuclear@23
|
287 obj.f.push_back(face);
|
nuclear@23
|
288 }
|
nuclear@23
|
289 break;
|
nuclear@23
|
290
|
nuclear@23
|
291 default:
|
nuclear@23
|
292 break; // ignore unknown commands
|
nuclear@23
|
293 }
|
nuclear@23
|
294
|
nuclear@23
|
295 prev_cmd = cmd;
|
nuclear@23
|
296 }
|
nuclear@23
|
297
|
nuclear@23
|
298 // reached end of file...
|
nuclear@23
|
299 if(!obj.f.empty()) {
|
nuclear@23
|
300 Mesh *mesh = cons_mesh(&obj);
|
nuclear@23
|
301 mesh->matid = matnames[obj.cur_mat];
|
nuclear@23
|
302 add_mesh(mesh);
|
nuclear@23
|
303 obj_added++;
|
nuclear@23
|
304 }
|
nuclear@23
|
305
|
nuclear@23
|
306 return obj_added > 0;
|
nuclear@23
|
307 }
|
nuclear@23
|
308
|
nuclear@23
|
309 static Mesh *cons_mesh(obj_file *obj)
|
nuclear@23
|
310 {
|
nuclear@23
|
311 Mesh *mesh;
|
nuclear@23
|
312
|
nuclear@23
|
313 // need at least one of each element
|
nuclear@23
|
314 bool added_norm = false, added_tc = false;
|
nuclear@23
|
315 if(obj->vn.empty()) {
|
nuclear@23
|
316 obj->vn.push_back(Vector3(0, 0, 0));
|
nuclear@23
|
317 added_norm = true;
|
nuclear@23
|
318 }
|
nuclear@23
|
319 if(obj->vt.empty()) {
|
nuclear@23
|
320 obj->vt.push_back(Vector3(0, 0, 0));
|
nuclear@23
|
321 added_tc = true;
|
nuclear@23
|
322 }
|
nuclear@23
|
323
|
nuclear@23
|
324 mesh = new Mesh;
|
nuclear@23
|
325
|
nuclear@23
|
326 for(size_t i=0; i<obj->f.size(); i++) {
|
nuclear@23
|
327 Face face;
|
nuclear@23
|
328 Vector3 v[3];
|
nuclear@23
|
329
|
nuclear@23
|
330 for(int j=0; j<3; j++) {
|
nuclear@23
|
331 obj_face *f = &obj->f[i];
|
nuclear@23
|
332
|
nuclear@23
|
333 face.v[j].pos[0] = v[j].x = obj->v[f->v[j]].x;
|
nuclear@23
|
334 face.v[j].pos[1] = v[j].y = obj->v[f->v[j]].y;
|
nuclear@23
|
335 face.v[j].pos[2] = v[j].z = obj->v[f->v[j]].z;
|
nuclear@23
|
336 face.v[j].pos[3] = 0.0;
|
nuclear@23
|
337
|
nuclear@23
|
338 int nidx = f->n[j] < 0 ? 0 : f->n[j];
|
nuclear@23
|
339 face.v[j].normal[0] = obj->vn[nidx].x;
|
nuclear@23
|
340 face.v[j].normal[1] = obj->vn[nidx].y;
|
nuclear@23
|
341 face.v[j].normal[2] = obj->vn[nidx].z;
|
nuclear@23
|
342 face.v[j].normal[3] = 0.0;
|
nuclear@23
|
343
|
nuclear@23
|
344 int tidx = f->t[j] < 0 ? 0 : f->t[j];
|
nuclear@23
|
345 face.v[j].tex[0] = obj->vt[tidx].x;
|
nuclear@23
|
346 face.v[j].tex[1] = obj->vt[tidx].y;
|
nuclear@23
|
347 }
|
nuclear@23
|
348
|
nuclear@23
|
349 Vector3 a = v[1] - v[0];
|
nuclear@23
|
350 Vector3 b = v[2] - v[0];
|
nuclear@23
|
351 Vector3 n = cross(a, b);
|
nuclear@23
|
352 n.normalize();
|
nuclear@23
|
353
|
nuclear@23
|
354 face.normal[0] = n.x;
|
nuclear@23
|
355 face.normal[1] = n.y;
|
nuclear@23
|
356 face.normal[2] = n.z;
|
nuclear@23
|
357 face.normal[3] = 0.0;
|
nuclear@23
|
358
|
nuclear@23
|
359 mesh->faces.push_back(face);
|
nuclear@23
|
360 }
|
nuclear@23
|
361
|
nuclear@23
|
362 if(added_norm) {
|
nuclear@23
|
363 obj->vn.pop_back();
|
nuclear@23
|
364 }
|
nuclear@23
|
365 if(added_tc) {
|
nuclear@23
|
366 obj->vt.pop_back();
|
nuclear@23
|
367 }
|
nuclear@23
|
368
|
nuclear@23
|
369 return mesh;
|
nuclear@23
|
370 }
|
nuclear@23
|
371
|
nuclear@23
|
372 static bool read_materials(FILE *fp, std::vector<obj_mat> *vmtl)
|
nuclear@23
|
373 {
|
nuclear@23
|
374 obj_mat mat;
|
nuclear@23
|
375
|
nuclear@23
|
376 for(;;) {
|
nuclear@23
|
377 char line[BUF_SZ];
|
nuclear@23
|
378 fgets(line, sizeof line, fp);
|
nuclear@23
|
379 if(feof(fp)) {
|
nuclear@23
|
380 break;
|
nuclear@23
|
381 }
|
nuclear@23
|
382
|
nuclear@23
|
383 char *tok;
|
nuclear@23
|
384 if(!(tok = strtok(line, SEP))) {
|
nuclear@23
|
385 continue;
|
nuclear@23
|
386 }
|
nuclear@23
|
387
|
nuclear@23
|
388 int cmd;
|
nuclear@23
|
389 if((cmd = get_cmd(tok)) == -1) {
|
nuclear@23
|
390 continue;
|
nuclear@23
|
391 }
|
nuclear@23
|
392
|
nuclear@23
|
393 switch(cmd) {
|
nuclear@23
|
394 case CMD_NEWMTL:
|
nuclear@23
|
395 // add the previous material, and start a new one
|
nuclear@23
|
396 if(mat.name.length() > 0) {
|
nuclear@23
|
397 printf("Adding material: %s\n", mat.name.c_str());
|
nuclear@23
|
398 vmtl->push_back(mat);
|
nuclear@23
|
399 mat.reset();
|
nuclear@23
|
400 }
|
nuclear@23
|
401 if((tok = strtok(0, SEP))) {
|
nuclear@23
|
402 mat.name = tok;
|
nuclear@23
|
403 }
|
nuclear@23
|
404 break;
|
nuclear@23
|
405
|
nuclear@23
|
406 case CMD_KA:
|
nuclear@23
|
407 parse_color(&mat.ambient);
|
nuclear@23
|
408 break;
|
nuclear@23
|
409
|
nuclear@23
|
410 case CMD_KD:
|
nuclear@23
|
411 parse_color(&mat.diffuse);
|
nuclear@23
|
412 break;
|
nuclear@23
|
413
|
nuclear@23
|
414 case CMD_KS:
|
nuclear@23
|
415 parse_color(&mat.specular);
|
nuclear@23
|
416 break;
|
nuclear@23
|
417
|
nuclear@23
|
418 case CMD_KR:
|
nuclear@23
|
419 if((tok = strtok(0, SEP)) && is_float(tok)) {
|
nuclear@23
|
420 mat.refl = atof(tok);
|
nuclear@23
|
421 }
|
nuclear@23
|
422 break;
|
nuclear@23
|
423
|
nuclear@23
|
424 case CMD_NS:
|
nuclear@23
|
425 if((tok = strtok(0, SEP)) && is_float(tok)) {
|
nuclear@23
|
426 mat.shininess = atof(tok);
|
nuclear@23
|
427 }
|
nuclear@23
|
428 break;
|
nuclear@23
|
429
|
nuclear@23
|
430 case CMD_NI:
|
nuclear@23
|
431 if((tok = strtok(0, SEP)) && is_float(tok)) {
|
nuclear@23
|
432 mat.ior = atof(tok);
|
nuclear@23
|
433 }
|
nuclear@23
|
434 break;
|
nuclear@23
|
435
|
nuclear@23
|
436 case CMD_D:
|
nuclear@23
|
437 case CMD_TR:
|
nuclear@23
|
438 {
|
nuclear@23
|
439 Vector3 c;
|
nuclear@23
|
440 if(parse_color(&c)) {
|
nuclear@23
|
441 mat.alpha = cmd == CMD_D ? c.x : 1.0 - c.x;
|
nuclear@23
|
442 }
|
nuclear@23
|
443 }
|
nuclear@23
|
444 break;
|
nuclear@23
|
445
|
nuclear@23
|
446 case CMD_MAP_KD:
|
nuclear@23
|
447 mat.tex_dif = parse_map();
|
nuclear@23
|
448 break;
|
nuclear@23
|
449
|
nuclear@23
|
450 default:
|
nuclear@23
|
451 break;
|
nuclear@23
|
452 }
|
nuclear@23
|
453 }
|
nuclear@23
|
454
|
nuclear@23
|
455 if(mat.name.length() > 0) {
|
nuclear@23
|
456 printf("Adding material: %s\n", mat.name.c_str());
|
nuclear@23
|
457 vmtl->push_back(mat);
|
nuclear@23
|
458 }
|
nuclear@23
|
459 return true;
|
nuclear@23
|
460 }
|
nuclear@23
|
461
|
nuclear@23
|
462 static int get_cmd(char *str)
|
nuclear@23
|
463 {
|
nuclear@23
|
464 char *s = str;
|
nuclear@23
|
465 while((*s = toupper(*s))) s++;
|
nuclear@23
|
466
|
nuclear@23
|
467 for(int i=0; cmd_names[i]; i++) {
|
nuclear@23
|
468 if(strcmp(str, cmd_names[i]) == 0) {
|
nuclear@23
|
469 return i;
|
nuclear@23
|
470 }
|
nuclear@23
|
471 }
|
nuclear@23
|
472 return CMD_UNK;
|
nuclear@23
|
473 }
|
nuclear@23
|
474
|
nuclear@23
|
475 static bool is_int(const char *str)
|
nuclear@23
|
476 {
|
nuclear@23
|
477 char *tmp;
|
nuclear@23
|
478 strtol(str, &tmp, 10);
|
nuclear@23
|
479 return tmp != str;
|
nuclear@23
|
480 }
|
nuclear@23
|
481
|
nuclear@23
|
482 static bool is_float(const char *str)
|
nuclear@23
|
483 {
|
nuclear@23
|
484 char *tmp;
|
nuclear@23
|
485 strtod(str, &tmp);
|
nuclear@23
|
486 return tmp != str;
|
nuclear@23
|
487 }
|
nuclear@23
|
488
|
nuclear@23
|
489 static bool parse_vec(Vector3 *vec)
|
nuclear@23
|
490 {
|
nuclear@23
|
491 for(int i=0; i<3; i++) {
|
nuclear@23
|
492 char *tok;
|
nuclear@23
|
493
|
nuclear@23
|
494 if(!(tok = strtok(0, SEP)) || !is_float(tok)) {
|
nuclear@23
|
495 if(i < 2) {
|
nuclear@23
|
496 return false;
|
nuclear@23
|
497 }
|
nuclear@23
|
498 vec->z = 0.0;
|
nuclear@23
|
499 } else {
|
nuclear@23
|
500 float v = atof(tok);
|
nuclear@23
|
501
|
nuclear@23
|
502 switch(i) {
|
nuclear@23
|
503 case 0:
|
nuclear@23
|
504 vec->x = v;
|
nuclear@23
|
505 break;
|
nuclear@23
|
506 case 1:
|
nuclear@23
|
507 vec->y = v;
|
nuclear@23
|
508 break;
|
nuclear@23
|
509 case 2:
|
nuclear@23
|
510 vec->z = v;
|
nuclear@23
|
511 break;
|
nuclear@23
|
512 }
|
nuclear@23
|
513 }
|
nuclear@23
|
514 }
|
nuclear@23
|
515 return true;
|
nuclear@23
|
516 }
|
nuclear@23
|
517
|
nuclear@23
|
518 static bool parse_color(Vector3 *col)
|
nuclear@23
|
519 {
|
nuclear@23
|
520 for(int i=0; i<3; i++) {
|
nuclear@23
|
521 char *tok;
|
nuclear@23
|
522
|
nuclear@23
|
523 if(!(tok = strtok(0, SEP)) || !is_float(tok)) {
|
nuclear@23
|
524 col->y = col->z = col->x;
|
nuclear@23
|
525 return i > 0 ? true : false;
|
nuclear@23
|
526 }
|
nuclear@23
|
527
|
nuclear@23
|
528 float v = atof(tok);
|
nuclear@23
|
529 switch(i) {
|
nuclear@23
|
530 case 0:
|
nuclear@23
|
531 col->x = v;
|
nuclear@23
|
532 break;
|
nuclear@23
|
533 case 1:
|
nuclear@23
|
534 col->y = v;
|
nuclear@23
|
535 break;
|
nuclear@23
|
536 case 2:
|
nuclear@23
|
537 col->z = v;
|
nuclear@23
|
538 break;
|
nuclear@23
|
539 }
|
nuclear@23
|
540 }
|
nuclear@23
|
541 return true;
|
nuclear@23
|
542 }
|
nuclear@23
|
543
|
nuclear@23
|
544 static bool parse_face(obj_face *face)
|
nuclear@23
|
545 {
|
nuclear@23
|
546 char *tok[] = {0, 0, 0, 0};
|
nuclear@23
|
547 face->elem = 0;
|
nuclear@23
|
548
|
nuclear@23
|
549 for(int i=0; i<4; i++) {
|
nuclear@23
|
550 if((!(tok[i] = strtok(0, SEP)) || !is_int(tok[i]))) {
|
nuclear@23
|
551 if(i < 3) return false; // less than 3 verts? not a polygon
|
nuclear@23
|
552 } else {
|
nuclear@23
|
553 face->elem++;
|
nuclear@23
|
554 }
|
nuclear@23
|
555 }
|
nuclear@23
|
556
|
nuclear@23
|
557 for(int i=0; i<4; i++) {
|
nuclear@23
|
558 char *subtok = tok[i];
|
nuclear@23
|
559
|
nuclear@23
|
560 if(!subtok || !*subtok || !is_int(subtok)) {
|
nuclear@23
|
561 if(i < 3) {
|
nuclear@23
|
562 return false;
|
nuclear@23
|
563 }
|
nuclear@23
|
564 face->v[i] = INVALID_IDX;
|
nuclear@23
|
565 } else {
|
nuclear@23
|
566 face->v[i] = atoi(subtok);
|
nuclear@23
|
567 if(face->v[i] > 0) face->v[i]--; /* convert to 0-based */
|
nuclear@23
|
568 }
|
nuclear@23
|
569
|
nuclear@23
|
570 while(subtok && *subtok && *subtok != '/') {
|
nuclear@23
|
571 subtok++;
|
nuclear@23
|
572 }
|
nuclear@23
|
573 if(subtok && *subtok && *++subtok && is_int(subtok)) {
|
nuclear@23
|
574 face->t[i] = atoi(subtok);
|
nuclear@23
|
575 if(face->t[i] > 0) face->t[i]--; /* convert to 0-based */
|
nuclear@23
|
576 } else {
|
nuclear@23
|
577 face->t[i] = INVALID_IDX;
|
nuclear@23
|
578 }
|
nuclear@23
|
579
|
nuclear@23
|
580 while(subtok && *subtok && *subtok != '/') {
|
nuclear@23
|
581 subtok++;
|
nuclear@23
|
582 }
|
nuclear@23
|
583 if(subtok && *subtok && *++subtok && is_int(subtok)) {
|
nuclear@23
|
584 face->n[i] = atoi(subtok);
|
nuclear@23
|
585 if(face->n[i] > 0) face->n[i]--; /* convert to 0-based */
|
nuclear@23
|
586 } else {
|
nuclear@23
|
587 face->n[i] = INVALID_IDX;
|
nuclear@23
|
588 }
|
nuclear@23
|
589 }
|
nuclear@23
|
590
|
nuclear@23
|
591 return true;
|
nuclear@23
|
592 }
|
nuclear@23
|
593
|
nuclear@23
|
594 static const char *parse_map()
|
nuclear@23
|
595 {
|
nuclear@23
|
596 char *tok, *prev = 0;
|
nuclear@23
|
597
|
nuclear@23
|
598 while((tok = strtok(0, SEP))) {
|
nuclear@23
|
599 prev = tok;
|
nuclear@23
|
600 }
|
nuclear@23
|
601
|
nuclear@23
|
602 return prev ? prev : "";
|
nuclear@23
|
603 }
|
nuclear@23
|
604
|
nuclear@23
|
605 static bool find_file(char *res, int sz, const char *fname, const char *path, const char *mode)
|
nuclear@23
|
606 {
|
nuclear@23
|
607 FILE *fp;
|
nuclear@23
|
608 const char *beg, *end;
|
nuclear@23
|
609 int fnamelen = strlen(fname);
|
nuclear@23
|
610
|
nuclear@23
|
611 beg = path;
|
nuclear@23
|
612 while(beg && *beg) {
|
nuclear@23
|
613 end = beg;
|
nuclear@23
|
614 while(*end && *end != ':') {
|
nuclear@23
|
615 end++;
|
nuclear@23
|
616 }
|
nuclear@23
|
617
|
nuclear@23
|
618 int res_len = end - beg;
|
nuclear@23
|
619 char *pathname = (char*)alloca(res_len + fnamelen + 2);
|
nuclear@23
|
620 memcpy(pathname, beg, res_len);
|
nuclear@23
|
621 pathname[res_len] = 0;
|
nuclear@23
|
622 if(res_len) {
|
nuclear@23
|
623 strcat(pathname, "/");
|
nuclear@23
|
624 }
|
nuclear@23
|
625 strcat(pathname, fname);
|
nuclear@23
|
626
|
nuclear@23
|
627 if((fp = fopen(pathname, mode))) {
|
nuclear@23
|
628 fclose(fp);
|
nuclear@23
|
629 strncpy(res, pathname, sz);
|
nuclear@23
|
630 return true;
|
nuclear@23
|
631 }
|
nuclear@23
|
632
|
nuclear@23
|
633 beg += res_len;
|
nuclear@23
|
634 if(*beg == ':') beg++;
|
nuclear@23
|
635 }
|
nuclear@23
|
636 return false;
|
nuclear@23
|
637 }
|
nuclear@23
|
638
|
nuclear@23
|
639 static const char *dirname(const char *str)
|
nuclear@23
|
640 {
|
nuclear@23
|
641 static char buf[PATH_MAX];
|
nuclear@23
|
642
|
nuclear@23
|
643 if(!str || !*str) {
|
nuclear@23
|
644 strcpy(buf, ".");
|
nuclear@23
|
645 } else {
|
nuclear@23
|
646 strncpy(buf, str, PATH_MAX);
|
nuclear@23
|
647 char *ptr = strrchr(buf, '/');
|
nuclear@23
|
648
|
nuclear@23
|
649 if(ptr && *ptr) {
|
nuclear@23
|
650 *ptr = 0;
|
nuclear@23
|
651 } else {
|
nuclear@23
|
652 strcpy(buf, ".");
|
nuclear@23
|
653 }
|
nuclear@23
|
654 }
|
nuclear@23
|
655 return buf;
|
nuclear@23
|
656 }
|