clray

annotate src/mesh.cc @ 20:63a6b46f58a0

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