clray

annotate src/scene_obj.cc @ 59:eb97f9c92e1d

added the triangle clipping code, now I must actually use it...
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Sep 2010 07:27:12 +0100
parents
children 0f174fd60f19
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 }