rev |
line source |
nuclear@12
|
1 /*
|
nuclear@12
|
2 eqemu - electronic queue system emulator
|
nuclear@12
|
3 Copyright (C) 2014 John Tsiombikas <nuclear@member.fsf.org>,
|
nuclear@12
|
4 Eleni-Maria Stea <eleni@mutantstargoat.com>
|
nuclear@12
|
5
|
nuclear@12
|
6 This program is free software: you can redistribute it and/or modify
|
nuclear@12
|
7 it under the terms of the GNU General Public License as published by
|
nuclear@12
|
8 the Free Software Foundation, either version 3 of the License, or
|
nuclear@12
|
9 (at your option) any later version.
|
nuclear@12
|
10
|
nuclear@12
|
11 This program is distributed in the hope that it will be useful,
|
nuclear@12
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@12
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@12
|
14 GNU General Public License for more details.
|
nuclear@12
|
15
|
nuclear@12
|
16 You should have received a copy of the GNU General Public License
|
nuclear@12
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@12
|
18 */
|
nuclear@3
|
19 #include <stdlib.h>
|
nuclear@3
|
20 #include <string.h>
|
nuclear@3
|
21 #include <ctype.h>
|
nuclear@3
|
22 #include <limits.h>
|
nuclear@4
|
23 #include <assert.h>
|
nuclear@3
|
24 #include <vector>
|
nuclear@3
|
25 #include <map>
|
nuclear@3
|
26 #include <string>
|
nuclear@3
|
27 #include <sstream>
|
nuclear@3
|
28 #include <iomanip>
|
nuclear@3
|
29 #include "scene.h"
|
nuclear@3
|
30
|
nuclear@3
|
31 using namespace std;
|
nuclear@3
|
32
|
nuclear@3
|
33 #define COMMANDS \
|
nuclear@3
|
34 CMD(V), \
|
nuclear@3
|
35 CMD(VN), \
|
nuclear@3
|
36 CMD(VT), \
|
nuclear@3
|
37 CMD(F), \
|
nuclear@3
|
38 CMD(O), \
|
nuclear@3
|
39 CMD(G), \
|
nuclear@3
|
40 CMD(MTLLIB), \
|
nuclear@3
|
41 CMD(USEMTL), \
|
nuclear@3
|
42 CMD(NEWMTL), \
|
nuclear@6
|
43 CMD(KE), \
|
nuclear@3
|
44 CMD(KA), \
|
nuclear@3
|
45 CMD(KD), \
|
nuclear@3
|
46 CMD(KS), \
|
nuclear@3
|
47 CMD(NS), \
|
nuclear@3
|
48 CMD(NI), \
|
nuclear@3
|
49 CMD(D), \
|
nuclear@3
|
50 CMD(TR), \
|
nuclear@3
|
51 CMD(MAP_KD), \
|
nuclear@6
|
52 CMD(MAP_REFL), \
|
nuclear@6
|
53 CMD(MAP_BUMP), \
|
nuclear@3
|
54 CMD(MAP_KS), \
|
nuclear@3
|
55 CMD(MAP_NS), \
|
nuclear@3
|
56 CMD(MAP_D), \
|
nuclear@3
|
57 CMD(REFL), \
|
nuclear@3
|
58 CMD(BUMP)
|
nuclear@3
|
59
|
nuclear@3
|
60 #define CMD(x) CMD_##x
|
nuclear@3
|
61 enum {
|
nuclear@3
|
62 COMMANDS,
|
nuclear@3
|
63 CMD_UNK
|
nuclear@3
|
64 };
|
nuclear@3
|
65 #undef CMD
|
nuclear@3
|
66
|
nuclear@3
|
67 #define CMD(x) #x
|
nuclear@3
|
68 static const char *cmd_names[] = {
|
nuclear@3
|
69 COMMANDS,
|
nuclear@3
|
70 0
|
nuclear@3
|
71 };
|
nuclear@3
|
72 #undef CMD
|
nuclear@3
|
73
|
nuclear@3
|
74
|
nuclear@3
|
75 struct ObjFace {
|
nuclear@3
|
76 int elem;
|
nuclear@3
|
77 int v[4], n[4], t[4];
|
nuclear@3
|
78 };
|
nuclear@3
|
79
|
nuclear@3
|
80 struct ObjFile {
|
nuclear@3
|
81 string cur_obj, cur_mat;
|
nuclear@3
|
82 vector<Vector3> v, vn;
|
nuclear@3
|
83 vector<Vector2> vt;
|
nuclear@3
|
84 vector<ObjFace> f;
|
nuclear@3
|
85 };
|
nuclear@3
|
86
|
nuclear@3
|
87 typedef Vector3 Color;
|
nuclear@3
|
88
|
nuclear@3
|
89 struct ObjMat {
|
nuclear@3
|
90 string name; // newmtl <name>
|
nuclear@3
|
91 Color ambient, diffuse, specular; // Ka, Kd, Ks
|
nuclear@6
|
92 Color emissive; // Ke
|
nuclear@3
|
93 float shininess; // Ns
|
nuclear@3
|
94 float ior; // Ni
|
nuclear@3
|
95 float alpha; // d, Tr
|
nuclear@3
|
96
|
nuclear@3
|
97 string tex_dif, tex_spec, tex_shin, tex_alpha; // map_Kd, map_Ks, map_Ns, map_d
|
nuclear@3
|
98 string tex_refl; // refl -type sphere|cube file
|
nuclear@3
|
99 string tex_bump; // bump
|
nuclear@3
|
100
|
nuclear@3
|
101 ObjMat() { reset(); }
|
nuclear@3
|
102
|
nuclear@3
|
103 void reset() {
|
nuclear@3
|
104 ambient = diffuse = Color(0.5, 0.5, 0.5);
|
nuclear@3
|
105 specular = Color(0.0, 0.0, 0.0);
|
nuclear@3
|
106 name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = "";
|
nuclear@3
|
107 shininess = 0;
|
nuclear@3
|
108 ior = alpha = 1;
|
nuclear@3
|
109 }
|
nuclear@3
|
110 };
|
nuclear@3
|
111
|
nuclear@3
|
112 static bool read_materials(FILE *fp, vector<ObjMat> *vmtl);
|
nuclear@3
|
113 static Object *cons_object(ObjFile *obj);
|
nuclear@3
|
114
|
nuclear@3
|
115 static int get_cmd(char *str);
|
nuclear@3
|
116 static bool is_int(const char *str);
|
nuclear@3
|
117 static bool is_float(const char *str);
|
nuclear@3
|
118 static bool parse_vec(Vector3 *vec);
|
nuclear@3
|
119 static bool parse_color(Color *col);
|
nuclear@3
|
120 static bool parse_face(ObjFace *face);
|
nuclear@3
|
121 static const char *parse_map();
|
nuclear@3
|
122
|
nuclear@3
|
123
|
nuclear@3
|
124 static map<string, Material> matlib;
|
nuclear@3
|
125
|
nuclear@3
|
126
|
nuclear@3
|
127 #define INVALID_IDX INT_MIN
|
nuclear@3
|
128
|
nuclear@3
|
129 #define SEP " \t\n\r\v"
|
nuclear@3
|
130 #define BUF_SZ 512
|
nuclear@3
|
131 bool Scene::load_obj(FILE *fp)
|
nuclear@3
|
132 {
|
nuclear@3
|
133 static int seq;
|
nuclear@3
|
134 char cur_name[16];
|
nuclear@3
|
135 stringstream sstr;
|
nuclear@3
|
136
|
nuclear@3
|
137 ObjFile obj;
|
nuclear@3
|
138
|
nuclear@3
|
139 sprintf(cur_name, "default%02d.obj", seq++);
|
nuclear@3
|
140 obj.cur_obj = cur_name;
|
nuclear@3
|
141
|
nuclear@3
|
142 int prev_cmd = 0, obj_added = 0;
|
nuclear@3
|
143 for(;;) {
|
nuclear@3
|
144 Vector3 vec;
|
nuclear@3
|
145 ObjFace face;
|
nuclear@3
|
146
|
nuclear@3
|
147 char line[BUF_SZ];
|
nuclear@3
|
148 fgets(line, sizeof line, fp);
|
nuclear@3
|
149 if(feof(fp)) {
|
nuclear@3
|
150 break;
|
nuclear@3
|
151 }
|
nuclear@3
|
152
|
nuclear@3
|
153 char *tok;
|
nuclear@3
|
154 if(!(tok = strtok(line, SEP))) {
|
nuclear@3
|
155 continue; // ignore empty lines
|
nuclear@3
|
156 }
|
nuclear@3
|
157
|
nuclear@3
|
158 int cmd;
|
nuclear@3
|
159 if((cmd = get_cmd(tok)) == -1) {
|
nuclear@3
|
160 continue; // ignore unknown commands ...
|
nuclear@3
|
161 }
|
nuclear@3
|
162
|
nuclear@3
|
163 switch(cmd) {
|
nuclear@3
|
164 case CMD_V:
|
nuclear@3
|
165 if(!parse_vec(&vec)) {
|
nuclear@3
|
166 continue;
|
nuclear@3
|
167 }
|
nuclear@3
|
168 obj.v.push_back(vec);
|
nuclear@3
|
169 break;
|
nuclear@3
|
170
|
nuclear@3
|
171 case CMD_VN:
|
nuclear@3
|
172 if(!parse_vec(&vec)) {
|
nuclear@3
|
173 continue;
|
nuclear@3
|
174 }
|
nuclear@3
|
175 obj.vn.push_back(vec);
|
nuclear@3
|
176 break;
|
nuclear@3
|
177
|
nuclear@3
|
178 case CMD_VT:
|
nuclear@3
|
179 if(!parse_vec(&vec)) {
|
nuclear@3
|
180 continue;
|
nuclear@3
|
181 }
|
nuclear@3
|
182 vec.y = 1.0 - vec.y;
|
nuclear@3
|
183 obj.vt.push_back(Vector2(vec.x, vec.y));
|
nuclear@3
|
184 break;
|
nuclear@3
|
185
|
nuclear@3
|
186 case CMD_O:
|
nuclear@3
|
187 case CMD_G:
|
nuclear@3
|
188 if(prev_cmd == CMD_O || prev_cmd == CMD_G) {
|
nuclear@3
|
189 break; // just in case we've got both of them in a row
|
nuclear@3
|
190 }
|
nuclear@3
|
191 /* if we have any previous data, group them up, add the object
|
nuclear@3
|
192 * and continue with the new one...
|
nuclear@3
|
193 */
|
nuclear@3
|
194 if(!obj.f.empty()) {
|
nuclear@3
|
195 Object *robj = cons_object(&obj);
|
nuclear@3
|
196 robj->mtl = matlib[obj.cur_mat];
|
nuclear@3
|
197 add_object(robj);
|
nuclear@3
|
198 obj_added++;
|
nuclear@3
|
199
|
nuclear@3
|
200 obj.f.clear(); // clean the face list
|
nuclear@3
|
201 }
|
nuclear@3
|
202 if((tok = strtok(0, SEP))) {
|
nuclear@3
|
203 obj.cur_obj = tok;
|
nuclear@3
|
204 } else {
|
nuclear@3
|
205 sprintf(cur_name, "default%02d.obj", seq++);
|
nuclear@3
|
206 obj.cur_obj = cur_name;
|
nuclear@3
|
207 }
|
nuclear@3
|
208 break;
|
nuclear@3
|
209
|
nuclear@3
|
210 case CMD_MTLLIB:
|
nuclear@3
|
211 if((tok = strtok(0, SEP))) {
|
nuclear@3
|
212 FILE *mfile;
|
nuclear@3
|
213 if(!(mfile = fopen(tok, "rb"))) {
|
nuclear@3
|
214 fprintf(stderr, "failed to open material library: %s\n", tok);
|
nuclear@3
|
215 continue;
|
nuclear@3
|
216 }
|
nuclear@3
|
217
|
nuclear@3
|
218 // load all materials of the mtl file into a vector
|
nuclear@3
|
219 vector<ObjMat> vmtl;
|
nuclear@3
|
220 if(!read_materials(mfile, &vmtl)) {
|
nuclear@3
|
221 continue;
|
nuclear@3
|
222 }
|
nuclear@3
|
223 fclose(mfile);
|
nuclear@3
|
224
|
nuclear@3
|
225 // and add them all to the scene
|
nuclear@3
|
226 for(size_t i=0; i<vmtl.size(); i++) {
|
nuclear@3
|
227 Material mat;
|
nuclear@3
|
228 mat.ambient = vmtl[i].ambient;
|
nuclear@3
|
229 mat.diffuse = vmtl[i].diffuse;
|
nuclear@3
|
230 mat.specular = vmtl[i].specular;
|
nuclear@3
|
231 mat.shininess = vmtl[i].shininess;
|
nuclear@6
|
232 mat.emissive = vmtl[i].emissive;
|
nuclear@3
|
233 mat.alpha = vmtl[i].alpha;
|
nuclear@3
|
234
|
nuclear@5
|
235 if(vmtl[i].tex_dif.length()) {
|
nuclear@5
|
236 mat.tex[TEX_DIFFUSE] = load_texture(vmtl[i].tex_dif.c_str());
|
nuclear@5
|
237 }
|
nuclear@5
|
238 if(vmtl[i].tex_refl.length()) {
|
nuclear@5
|
239 mat.tex[TEX_ENVMAP] = load_texture(vmtl[i].tex_refl.c_str());
|
nuclear@5
|
240 }
|
nuclear@3
|
241
|
nuclear@3
|
242 matlib[vmtl[i].name] = mat;
|
nuclear@3
|
243 }
|
nuclear@3
|
244 }
|
nuclear@3
|
245 break;
|
nuclear@3
|
246
|
nuclear@3
|
247 case CMD_USEMTL:
|
nuclear@3
|
248 if((tok = strtok(0, SEP))) {
|
nuclear@3
|
249 obj.cur_mat = tok;
|
nuclear@3
|
250 } else {
|
nuclear@3
|
251 obj.cur_mat = "";
|
nuclear@3
|
252 }
|
nuclear@3
|
253 break;
|
nuclear@3
|
254
|
nuclear@3
|
255 case CMD_F:
|
nuclear@3
|
256 if(!parse_face(&face)) {
|
nuclear@3
|
257 continue;
|
nuclear@3
|
258 }
|
nuclear@3
|
259
|
nuclear@3
|
260 // convert negative indices to regular indices
|
nuclear@3
|
261 for(int i=0; i<4; i++) {
|
nuclear@3
|
262 if(face.v[i] < 0 && face.v[i] != INVALID_IDX) {
|
nuclear@3
|
263 face.v[i] = obj.v.size() + face.v[i];
|
nuclear@3
|
264 }
|
nuclear@3
|
265 if(face.n[i] < 0 && face.n[i] != INVALID_IDX) {
|
nuclear@3
|
266 face.n[i] = obj.vn.size() + face.n[i];
|
nuclear@3
|
267 }
|
nuclear@3
|
268 if(face.t[i] < 0 && face.t[i] != INVALID_IDX) {
|
nuclear@3
|
269 face.t[i] = obj.vt.size() + face.t[i];
|
nuclear@3
|
270 }
|
nuclear@3
|
271 }
|
nuclear@3
|
272
|
nuclear@3
|
273 // break quads into triangles if needed
|
nuclear@3
|
274 obj.f.push_back(face);
|
nuclear@3
|
275 if(face.elem == 4) {
|
nuclear@3
|
276 face.v[1] = face.v[2];
|
nuclear@3
|
277 face.n[1] = face.n[2];
|
nuclear@3
|
278 face.t[1] = face.t[2];
|
nuclear@3
|
279
|
nuclear@3
|
280 face.v[2] = face.v[3];
|
nuclear@3
|
281 face.n[2] = face.n[3];
|
nuclear@3
|
282 face.t[2] = face.t[3];
|
nuclear@3
|
283
|
nuclear@3
|
284 obj.f.push_back(face);
|
nuclear@3
|
285 }
|
nuclear@3
|
286 break;
|
nuclear@3
|
287
|
nuclear@3
|
288 default:
|
nuclear@3
|
289 break; // ignore unknown commands
|
nuclear@3
|
290 }
|
nuclear@3
|
291
|
nuclear@3
|
292 prev_cmd = cmd;
|
nuclear@3
|
293 }
|
nuclear@3
|
294
|
nuclear@3
|
295 // reached end of file...
|
nuclear@3
|
296 if(!obj.f.empty()) {
|
nuclear@3
|
297 Object *robj = cons_object(&obj);
|
nuclear@3
|
298 robj->mtl = matlib[obj.cur_mat];
|
nuclear@3
|
299 add_object(robj);
|
nuclear@3
|
300 obj_added++;
|
nuclear@3
|
301 }
|
nuclear@3
|
302
|
nuclear@3
|
303 return obj_added > 0;
|
nuclear@3
|
304 }
|
nuclear@3
|
305
|
nuclear@3
|
306 static Object *cons_object(ObjFile *obj)
|
nuclear@3
|
307 {
|
nuclear@3
|
308 Object *robj;
|
nuclear@3
|
309 Vector3 *varr, *narr;
|
nuclear@3
|
310 Vector2 *tarr;
|
nuclear@3
|
311
|
nuclear@3
|
312 int nelem = obj->f.size() * 3;
|
nuclear@3
|
313
|
nuclear@4
|
314 assert(sizeof(Vector3) == 3 * sizeof(float));
|
nuclear@4
|
315 assert(sizeof(Vector2) == 2 * sizeof(float));
|
nuclear@4
|
316
|
nuclear@3
|
317 try {
|
nuclear@3
|
318 robj = new Object;
|
nuclear@3
|
319 varr = new Vector3[nelem];
|
nuclear@3
|
320 narr = new Vector3[nelem];
|
nuclear@3
|
321 tarr = new Vector2[nelem];
|
nuclear@3
|
322 }
|
nuclear@3
|
323 catch(...) {
|
nuclear@3
|
324 return 0;
|
nuclear@3
|
325 }
|
nuclear@4
|
326 if(obj->cur_obj.length() > 0) {
|
nuclear@3
|
327 robj->set_name(obj->cur_obj.c_str());
|
nuclear@4
|
328 }
|
nuclear@3
|
329
|
nuclear@3
|
330 // need at least one of each element
|
nuclear@3
|
331 bool added_norm = false, added_tc = false;
|
nuclear@3
|
332 if(obj->vn.empty()) {
|
nuclear@3
|
333 obj->vn.push_back(Vector3(0, 0, 0));
|
nuclear@4
|
334 added_norm = true;
|
nuclear@3
|
335 }
|
nuclear@3
|
336 if(obj->vt.empty()) {
|
nuclear@3
|
337 obj->vt.push_back(Vector2(0, 0));
|
nuclear@3
|
338 added_tc = true;
|
nuclear@3
|
339 }
|
nuclear@3
|
340
|
nuclear@3
|
341 for(size_t i=0; i<obj->f.size(); i++) {
|
nuclear@3
|
342 for(int j=0; j<3; j++) {
|
nuclear@3
|
343 int idx = i * 3 + j;
|
nuclear@3
|
344 ObjFace *f = &obj->f[i];
|
nuclear@3
|
345
|
nuclear@3
|
346 varr[idx] = obj->v[f->v[j]];
|
nuclear@3
|
347 narr[idx] = obj->vn[f->n[j] < 0 ? 0 : f->n[j]];
|
nuclear@3
|
348
|
nuclear@3
|
349 float t = obj->vt[f->t[j] < 0 ? 0 : f->t[j]].x;
|
nuclear@3
|
350 float s = obj->vt[f->t[j] < 0 ? 0 : f->t[j]].y;
|
nuclear@3
|
351 tarr[idx] = Vector2(t, s);
|
nuclear@3
|
352 }
|
nuclear@3
|
353 }
|
nuclear@3
|
354
|
nuclear@3
|
355 if(added_norm) {
|
nuclear@3
|
356 obj->vn.pop_back();
|
nuclear@3
|
357 }
|
nuclear@3
|
358 if(added_tc) {
|
nuclear@3
|
359 obj->vt.pop_back();
|
nuclear@3
|
360 }
|
nuclear@3
|
361
|
nuclear@4
|
362 Mesh *mesh = new Mesh;
|
nuclear@3
|
363 mesh->set_attrib(MESH_ATTR_VERTEX, nelem, 3, &varr->x);
|
nuclear@3
|
364 mesh->set_attrib(MESH_ATTR_NORMAL, nelem, 3, &narr->x);
|
nuclear@3
|
365 mesh->set_attrib(MESH_ATTR_TEXCOORD, nelem, 2, &tarr->x);
|
nuclear@4
|
366 robj->set_mesh(mesh);
|
nuclear@4
|
367
|
nuclear@4
|
368 printf("loaded object %s: %d faces\n", obj->cur_obj.c_str(), nelem / 3);
|
nuclear@3
|
369
|
nuclear@3
|
370 delete [] varr;
|
nuclear@3
|
371 delete [] narr;
|
nuclear@3
|
372 delete [] tarr;
|
nuclear@3
|
373 return robj;
|
nuclear@3
|
374 }
|
nuclear@3
|
375
|
nuclear@3
|
376 static bool read_materials(FILE *fp, vector<ObjMat> *vmtl)
|
nuclear@3
|
377 {
|
nuclear@3
|
378 ObjMat mat;
|
nuclear@3
|
379
|
nuclear@3
|
380 for(;;) {
|
nuclear@3
|
381 char line[BUF_SZ];
|
nuclear@3
|
382 fgets(line, sizeof line, fp);
|
nuclear@3
|
383 if(feof(fp)) {
|
nuclear@3
|
384 break;
|
nuclear@3
|
385 }
|
nuclear@3
|
386
|
nuclear@3
|
387 char *tok;
|
nuclear@3
|
388 if(!(tok = strtok(line, SEP))) {
|
nuclear@3
|
389 continue;
|
nuclear@3
|
390 }
|
nuclear@3
|
391
|
nuclear@3
|
392 int cmd;
|
nuclear@3
|
393 if((cmd = get_cmd(tok)) == -1) {
|
nuclear@3
|
394 continue;
|
nuclear@3
|
395 }
|
nuclear@3
|
396
|
nuclear@3
|
397 switch(cmd) {
|
nuclear@3
|
398 case CMD_NEWMTL:
|
nuclear@3
|
399 // add the previous material, and start a new one
|
nuclear@3
|
400 if(mat.name.length() > 0) {
|
nuclear@3
|
401 vmtl->push_back(mat);
|
nuclear@3
|
402 mat.reset();
|
nuclear@3
|
403 }
|
nuclear@3
|
404 if((tok = strtok(0, SEP))) {
|
nuclear@3
|
405 mat.name = tok;
|
nuclear@3
|
406 }
|
nuclear@3
|
407 break;
|
nuclear@3
|
408
|
nuclear@6
|
409 case CMD_KE:
|
nuclear@6
|
410 parse_color(&mat.emissive);
|
nuclear@6
|
411 break;
|
nuclear@6
|
412
|
nuclear@3
|
413 case CMD_KA:
|
nuclear@3
|
414 parse_color(&mat.ambient);
|
nuclear@3
|
415 break;
|
nuclear@3
|
416
|
nuclear@3
|
417 case CMD_KD:
|
nuclear@3
|
418 parse_color(&mat.diffuse);
|
nuclear@3
|
419 break;
|
nuclear@3
|
420
|
nuclear@3
|
421 case CMD_KS:
|
nuclear@3
|
422 parse_color(&mat.specular);
|
nuclear@3
|
423 break;
|
nuclear@3
|
424
|
nuclear@3
|
425 case CMD_NS:
|
nuclear@3
|
426 if((tok = strtok(0, SEP)) && is_float(tok)) {
|
nuclear@3
|
427 mat.shininess = atof(tok);
|
nuclear@3
|
428 }
|
nuclear@3
|
429 break;
|
nuclear@3
|
430
|
nuclear@3
|
431 case CMD_NI:
|
nuclear@3
|
432 if((tok = strtok(0, SEP)) && is_float(tok)) {
|
nuclear@3
|
433 mat.ior = atof(tok);
|
nuclear@3
|
434 }
|
nuclear@3
|
435 break;
|
nuclear@3
|
436
|
nuclear@3
|
437 case CMD_D:
|
nuclear@3
|
438 case CMD_TR:
|
nuclear@3
|
439 {
|
nuclear@3
|
440 Color c;
|
nuclear@3
|
441 if(parse_color(&c)) {
|
nuclear@3
|
442 mat.alpha = cmd == CMD_D ? c.x : 1.0 - c.x;
|
nuclear@3
|
443 }
|
nuclear@3
|
444 }
|
nuclear@3
|
445 break;
|
nuclear@3
|
446
|
nuclear@3
|
447 case CMD_MAP_KD:
|
nuclear@3
|
448 mat.tex_dif = parse_map();
|
nuclear@3
|
449 break;
|
nuclear@3
|
450
|
nuclear@6
|
451 case CMD_MAP_REFL:
|
nuclear@6
|
452 mat.tex_refl = parse_map();
|
nuclear@6
|
453 break;
|
nuclear@6
|
454
|
nuclear@3
|
455 default:
|
nuclear@3
|
456 break;
|
nuclear@3
|
457 }
|
nuclear@3
|
458 }
|
nuclear@3
|
459
|
nuclear@3
|
460 if(mat.name.length() > 0) {
|
nuclear@3
|
461 vmtl->push_back(mat);
|
nuclear@3
|
462 }
|
nuclear@3
|
463 return true;
|
nuclear@3
|
464 }
|
nuclear@3
|
465
|
nuclear@3
|
466 static int get_cmd(char *str)
|
nuclear@3
|
467 {
|
nuclear@3
|
468 char *s = str;
|
nuclear@3
|
469 while((*s = toupper(*s))) s++;
|
nuclear@3
|
470
|
nuclear@3
|
471 for(int i=0; cmd_names[i]; i++) {
|
nuclear@3
|
472 if(strcmp(str, cmd_names[i]) == 0) {
|
nuclear@3
|
473 return i;
|
nuclear@3
|
474 }
|
nuclear@3
|
475 }
|
nuclear@3
|
476 return CMD_UNK;
|
nuclear@3
|
477 }
|
nuclear@3
|
478
|
nuclear@3
|
479 static bool is_int(const char *str)
|
nuclear@3
|
480 {
|
nuclear@3
|
481 char *tmp;
|
nuclear@3
|
482 strtol(str, &tmp, 10);
|
nuclear@3
|
483 return tmp != str;
|
nuclear@3
|
484 }
|
nuclear@3
|
485
|
nuclear@3
|
486 static bool is_float(const char *str)
|
nuclear@3
|
487 {
|
nuclear@3
|
488 char *tmp;
|
nuclear@3
|
489 strtod(str, &tmp);
|
nuclear@3
|
490 return tmp != str;
|
nuclear@3
|
491 }
|
nuclear@3
|
492
|
nuclear@3
|
493 static bool parse_vec(Vector3 *vec)
|
nuclear@3
|
494 {
|
nuclear@3
|
495 for(int i=0; i<3; i++) {
|
nuclear@3
|
496 char *tok;
|
nuclear@3
|
497
|
nuclear@3
|
498 if(!(tok = strtok(0, SEP)) || !is_float(tok)) {
|
nuclear@3
|
499 if(i < 2) {
|
nuclear@3
|
500 return false;
|
nuclear@3
|
501 }
|
nuclear@3
|
502 vec->z = 0.0;
|
nuclear@3
|
503 } else {
|
nuclear@3
|
504 (*vec)[i] = atof(tok);
|
nuclear@3
|
505 }
|
nuclear@3
|
506 }
|
nuclear@3
|
507 return true;
|
nuclear@3
|
508 }
|
nuclear@3
|
509
|
nuclear@3
|
510 static bool parse_color(Color *col)
|
nuclear@3
|
511 {
|
nuclear@3
|
512 for(int i=0; i<3; i++) {
|
nuclear@3
|
513 char *tok;
|
nuclear@3
|
514
|
nuclear@3
|
515 if(!(tok = strtok(0, SEP)) || !is_float(tok)) {
|
nuclear@3
|
516 col->y = col->z = col->x;
|
nuclear@3
|
517 return i > 0 ? true : false;
|
nuclear@3
|
518 }
|
nuclear@3
|
519 (*col)[i] = atof(tok);
|
nuclear@3
|
520 }
|
nuclear@3
|
521 return true;
|
nuclear@3
|
522 }
|
nuclear@3
|
523
|
nuclear@3
|
524 static bool parse_face(ObjFace *face)
|
nuclear@3
|
525 {
|
nuclear@3
|
526 char *tok[] = {0, 0, 0, 0};
|
nuclear@3
|
527 face->elem = 0;
|
nuclear@3
|
528
|
nuclear@3
|
529 for(int i=0; i<4; i++) {
|
nuclear@3
|
530 if((!(tok[i] = strtok(0, SEP)) || !is_int(tok[i]))) {
|
nuclear@3
|
531 if(i < 3) return false; // less than 3 verts? not a polygon
|
nuclear@3
|
532 } else {
|
nuclear@3
|
533 face->elem++;
|
nuclear@3
|
534 }
|
nuclear@3
|
535 }
|
nuclear@3
|
536
|
nuclear@3
|
537 for(int i=0; i<4; i++) {
|
nuclear@3
|
538 char *subtok = tok[i];
|
nuclear@3
|
539
|
nuclear@3
|
540 if(!subtok || !*subtok || !is_int(subtok)) {
|
nuclear@3
|
541 if(i < 3) {
|
nuclear@3
|
542 return false;
|
nuclear@3
|
543 }
|
nuclear@3
|
544 face->v[i] = INVALID_IDX;
|
nuclear@3
|
545 } else {
|
nuclear@3
|
546 face->v[i] = atoi(subtok);
|
nuclear@3
|
547 if(face->v[i] > 0) face->v[i]--; /* convert to 0-based */
|
nuclear@3
|
548 }
|
nuclear@3
|
549
|
nuclear@3
|
550 while(subtok && *subtok && *subtok != '/') {
|
nuclear@3
|
551 subtok++;
|
nuclear@3
|
552 }
|
nuclear@3
|
553 if(subtok && *subtok && *++subtok && is_int(subtok)) {
|
nuclear@3
|
554 face->t[i] = atoi(subtok);
|
nuclear@3
|
555 if(face->t[i] > 0) face->t[i]--; /* convert to 0-based */
|
nuclear@3
|
556 } else {
|
nuclear@3
|
557 face->t[i] = INVALID_IDX;
|
nuclear@3
|
558 }
|
nuclear@3
|
559
|
nuclear@3
|
560 while(subtok && *subtok && *subtok != '/') {
|
nuclear@3
|
561 subtok++;
|
nuclear@3
|
562 }
|
nuclear@3
|
563 if(subtok && *subtok && *++subtok && is_int(subtok)) {
|
nuclear@3
|
564 face->n[i] = atoi(subtok);
|
nuclear@3
|
565 if(face->n[i] > 0) face->n[i]--; /* convert to 0-based */
|
nuclear@3
|
566 } else {
|
nuclear@3
|
567 face->n[i] = INVALID_IDX;
|
nuclear@3
|
568 }
|
nuclear@3
|
569 }
|
nuclear@3
|
570
|
nuclear@3
|
571 return true;
|
nuclear@3
|
572 }
|
nuclear@3
|
573
|
nuclear@3
|
574 static const char *parse_map()
|
nuclear@3
|
575 {
|
nuclear@3
|
576 char *tok, *prev = 0;
|
nuclear@3
|
577
|
nuclear@3
|
578 while((tok = strtok(0, SEP))) {
|
nuclear@3
|
579 prev = tok;
|
nuclear@3
|
580 }
|
nuclear@3
|
581
|
nuclear@3
|
582 return prev ? prev : "";
|
nuclear@3
|
583 }
|