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