clray
diff src/scene.cc @ 22:6c44e4b1726d
OMG alignment is a bitch
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 11 Aug 2010 04:30:35 +0100 |
parents | src/mesh.cc@bd6c2b25f6e7 |
children | 51f115e337c2 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/scene.cc Wed Aug 11 04:30:35 2010 +0100 1.3 @@ -0,0 +1,755 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <math.h> 1.8 +#include <errno.h> 1.9 +#include <limits.h> 1.10 +#include <string> 1.11 +#include <vector> 1.12 +#include <map> 1.13 +#include "scene.h" 1.14 + 1.15 +#ifndef PATH_MAX 1.16 +#define PATH_MAX 512 1.17 +#endif 1.18 + 1.19 +using namespace std; 1.20 + 1.21 +#define COMMANDS \ 1.22 + CMD(V), \ 1.23 + CMD(VN), \ 1.24 + CMD(VT), \ 1.25 + CMD(F), \ 1.26 + CMD(O), \ 1.27 + CMD(G), \ 1.28 + CMD(MTLLIB), \ 1.29 + CMD(USEMTL), \ 1.30 + CMD(NEWMTL), \ 1.31 + CMD(KA), \ 1.32 + CMD(KD), \ 1.33 + CMD(KS), \ 1.34 + CMD(KR), \ 1.35 + CMD(NS), \ 1.36 + CMD(NI), \ 1.37 + CMD(D), \ 1.38 + CMD(TR), \ 1.39 + CMD(MAP_KD), \ 1.40 + CMD(MAP_KS), \ 1.41 + CMD(MAP_NS), \ 1.42 + CMD(MAP_D), \ 1.43 + CMD(REFL), \ 1.44 + CMD(BUMP) 1.45 + 1.46 +#define CMD(x) CMD_##x 1.47 +enum { 1.48 + COMMANDS, 1.49 + CMD_UNK 1.50 +}; 1.51 +#undef CMD 1.52 + 1.53 +#define CMD(x) #x 1.54 +static const char *cmd_names[] = { 1.55 + COMMANDS, 1.56 + 0 1.57 +}; 1.58 +#undef CMD 1.59 + 1.60 +struct Vector3 { 1.61 + float x, y, z; 1.62 + 1.63 + Vector3() { x = y = z = 0.0; } 1.64 + Vector3(float a, float b, float c) { x = a; y = b; z = c; } 1.65 + 1.66 + void normalize() { float len = sqrt(x * x + y * y + z * z); x /= len; y /= len; z /= len; } 1.67 +}; 1.68 + 1.69 +struct Vector2 { 1.70 + float x, y; 1.71 + 1.72 + Vector2() { x = y = 0.0; } 1.73 + Vector2(float a, float b) { x = a; y = b; } 1.74 +}; 1.75 + 1.76 +struct obj_face { 1.77 + int elem; 1.78 + int v[4], n[4], t[4]; 1.79 +}; 1.80 + 1.81 +struct obj_file { 1.82 + string cur_obj, cur_mat; 1.83 + vector<Vector3> v, vn, vt; 1.84 + vector<obj_face> f; 1.85 +}; 1.86 + 1.87 +struct obj_mat { 1.88 + string name; // newmtl <name> 1.89 + Vector3 ambient, diffuse, specular; // Ka, Kd, Ks 1.90 + float shininess; // Ns 1.91 + float ior; // Ni 1.92 + float alpha; // d, Tr 1.93 + float refl; // Kr (my extesnsion) 1.94 + 1.95 + string tex_dif, tex_spec, tex_shin, tex_alpha; // map_Kd, map_Ks, map_Ns, map_d 1.96 + string tex_refl; // refl -type sphere|cube file 1.97 + string tex_bump; // bump 1.98 + 1.99 + obj_mat() { reset(); } 1.100 + 1.101 + void reset() { 1.102 + ambient = diffuse = Vector3(0.5, 0.5, 0.5); 1.103 + specular = Vector3(0.0, 0.0, 0.0); 1.104 + name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = ""; 1.105 + shininess = 0; 1.106 + ior = alpha = 1; 1.107 + refl = 0.0; 1.108 + } 1.109 +}; 1.110 + 1.111 +static bool read_materials(FILE *fp, vector<obj_mat> *vmtl); 1.112 +static Mesh *cons_mesh(obj_file *obj); 1.113 + 1.114 +static int get_cmd(char *str); 1.115 +static bool is_int(const char *str); 1.116 +static bool is_float(const char *str); 1.117 +static bool parse_vec(Vector3 *vec); 1.118 +static bool parse_color(Vector3 *col); 1.119 +static bool parse_face(obj_face *face); 1.120 +static const char *parse_map(); 1.121 + 1.122 +static bool find_file(char *res, int sz, const char *fname, const char *path = ".", const char *mode = "rb"); 1.123 +static const char *dirname(const char *str); 1.124 + 1.125 +static Vector3 operator -(const Vector3 &a, const Vector3 &b); 1.126 +static Vector3 cross(const Vector3 &a, const Vector3 &b); 1.127 + 1.128 +static map<string, int> matnames; 1.129 + 1.130 + 1.131 +#define FEQ(a, b) (fabs((a) - (b)) < 1e-8) 1.132 +bool Face::operator ==(const Face &f) const 1.133 +{ 1.134 + for(int i=0; i<3; i++) { 1.135 + for(int j=0; j<3; j++) { 1.136 + if(!FEQ(v[i].pos[j], f.v[i].pos[j])) { 1.137 + return false; 1.138 + } 1.139 + if(!FEQ(v[i].normal[j], f.v[i].normal[j])) { 1.140 + return false; 1.141 + } 1.142 + } 1.143 + if(!FEQ(normal[i], f.normal[i])) { 1.144 + return false; 1.145 + } 1.146 + } 1.147 + return true; 1.148 +} 1.149 + 1.150 +bool Scene::add_mesh(Mesh *m) 1.151 +{ 1.152 + // make sure triangles have material ids 1.153 + for(size_t i=0; i<m->faces.size(); i++) { 1.154 + m->faces[i].matid = m->matid; 1.155 + } 1.156 + meshes.push_back(m); 1.157 + return true; 1.158 +} 1.159 + 1.160 +int Scene::get_num_meshes() const 1.161 +{ 1.162 + return (int)meshes.size(); 1.163 +} 1.164 + 1.165 +int Scene::get_num_faces() const 1.166 +{ 1.167 + int num_faces = 0; 1.168 + for(size_t i=0; i<meshes.size(); i++) { 1.169 + num_faces += meshes[i]->faces.size(); 1.170 + } 1.171 + return num_faces; 1.172 +} 1.173 + 1.174 +int Scene::get_num_materials() const 1.175 +{ 1.176 + return (int)matlib.size(); 1.177 +} 1.178 + 1.179 +Material *Scene::get_materials() 1.180 +{ 1.181 + if(matlib.empty()) { 1.182 + return 0; 1.183 + } 1.184 + return &matlib[0]; 1.185 +} 1.186 + 1.187 +const Material *Scene::get_materials() const 1.188 +{ 1.189 + if(matlib.empty()) { 1.190 + return 0; 1.191 + } 1.192 + return &matlib[0]; 1.193 +} 1.194 + 1.195 + 1.196 +#define INVALID_IDX INT_MIN 1.197 + 1.198 +#define SEP " \t\n\r\v" 1.199 +#define BUF_SZ 512 1.200 + 1.201 +bool Scene::load(const char *fname) 1.202 +{ 1.203 + FILE *fp; 1.204 + 1.205 + if(!(fp = fopen(fname, "rb"))) { 1.206 + fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno)); 1.207 + return false; 1.208 + } 1.209 + 1.210 + bool res = load(fp); 1.211 + fclose(fp); 1.212 + return res; 1.213 +} 1.214 + 1.215 +bool Scene::load(FILE *fp) 1.216 +{ 1.217 + static int seq; 1.218 + char cur_name[16]; 1.219 + 1.220 + obj_file obj; 1.221 + 1.222 + sprintf(cur_name, "default%02d.obj", seq++); 1.223 + obj.cur_obj = cur_name; 1.224 + 1.225 + int prev_cmd = 0, obj_added = 0; 1.226 + for(;;) { 1.227 + Vector3 vec; 1.228 + obj_face face; 1.229 + 1.230 + char line[BUF_SZ]; 1.231 + fgets(line, sizeof line, fp); 1.232 + if(feof(fp)) { 1.233 + break; 1.234 + } 1.235 + 1.236 + char *tok; 1.237 + if(!(tok = strtok(line, SEP))) { 1.238 + continue; // ignore empty lines 1.239 + } 1.240 + 1.241 + int cmd; 1.242 + if((cmd = get_cmd(tok)) == -1) { 1.243 + continue; // ignore unknown commands ... 1.244 + } 1.245 + 1.246 + switch(cmd) { 1.247 + case CMD_V: 1.248 + if(!parse_vec(&vec)) { 1.249 + continue; 1.250 + } 1.251 + obj.v.push_back(vec); 1.252 + break; 1.253 + 1.254 + case CMD_VN: 1.255 + if(!parse_vec(&vec)) { 1.256 + continue; 1.257 + } 1.258 + obj.vn.push_back(vec); 1.259 + break; 1.260 + 1.261 + case CMD_VT: 1.262 + if(!parse_vec(&vec)) { 1.263 + continue; 1.264 + } 1.265 + vec.y = 1.0 - vec.y; 1.266 + obj.vt.push_back(vec); 1.267 + break; 1.268 + 1.269 + case CMD_O: 1.270 + case CMD_G: 1.271 + if(prev_cmd == CMD_O || prev_cmd == CMD_G) { 1.272 + break; // just in case we've got both of them in a row 1.273 + } 1.274 + /* if we have any previous data, group them up, add the object 1.275 + * and continue with the new one... 1.276 + */ 1.277 + if(!obj.f.empty()) { 1.278 + Mesh *mesh = cons_mesh(&obj); 1.279 + mesh->matid = matnames[obj.cur_mat]; 1.280 + add_mesh(mesh); 1.281 + obj_added++; 1.282 + 1.283 + obj.f.clear(); // clean the face list 1.284 + } 1.285 + if((tok = strtok(0, SEP))) { 1.286 + obj.cur_obj = tok; 1.287 + } else { 1.288 + sprintf(cur_name, "default%02d.obj", seq++); 1.289 + obj.cur_obj = cur_name; 1.290 + } 1.291 + break; 1.292 + 1.293 + case CMD_MTLLIB: 1.294 + if((tok = strtok(0, SEP))) { 1.295 + char path[PATH_MAX]; 1.296 + 1.297 + sprintf(path, ".:%s", dirname(tok)); 1.298 + if(!find_file(path, PATH_MAX, tok, path)) { 1.299 + fprintf(stderr, "material library not found: %s\n", tok); 1.300 + continue; 1.301 + } 1.302 + 1.303 + FILE *mfile; 1.304 + if(!(mfile = fopen(path, "rb"))) { 1.305 + fprintf(stderr, "failed to open material library: %s\n", path); 1.306 + continue; 1.307 + } 1.308 + 1.309 + // load all materials of the mtl file into a vector 1.310 + vector<obj_mat> vmtl; 1.311 + if(!read_materials(mfile, &vmtl)) { 1.312 + continue; 1.313 + } 1.314 + fclose(mfile); 1.315 + 1.316 + // and add them all to the scene 1.317 + for(size_t i=0; i<vmtl.size(); i++) { 1.318 + Material mat; 1.319 + 1.320 + mat.kd[0] = vmtl[i].diffuse.x; 1.321 + mat.kd[1] = vmtl[i].diffuse.y; 1.322 + mat.kd[2] = vmtl[i].diffuse.z; 1.323 + 1.324 + mat.ks[0] = vmtl[i].specular.x; 1.325 + mat.ks[1] = vmtl[i].specular.y; 1.326 + mat.ks[2] = vmtl[i].specular.z; 1.327 + 1.328 + mat.kt = 1.0 - vmtl[i].alpha; 1.329 + mat.kr = vmtl[i].refl; 1.330 + mat.spow = vmtl[i].shininess; 1.331 + 1.332 + matlib.push_back(mat); 1.333 + matnames[vmtl[i].name] = i; 1.334 + } 1.335 + } 1.336 + break; 1.337 + 1.338 + case CMD_USEMTL: 1.339 + if((tok = strtok(0, SEP))) { 1.340 + obj.cur_mat = tok; 1.341 + } else { 1.342 + obj.cur_mat = ""; 1.343 + } 1.344 + break; 1.345 + 1.346 + case CMD_F: 1.347 + if(!parse_face(&face)) { 1.348 + continue; 1.349 + } 1.350 + 1.351 + // convert negative indices to regular indices 1.352 + for(int i=0; i<4; i++) { 1.353 + if(face.v[i] < 0 && face.v[i] != INVALID_IDX) { 1.354 + face.v[i] = obj.v.size() + face.v[i]; 1.355 + } 1.356 + if(face.n[i] < 0 && face.n[i] != INVALID_IDX) { 1.357 + face.n[i] = obj.vn.size() + face.n[i]; 1.358 + } 1.359 + if(face.t[i] < 0 && face.t[i] != INVALID_IDX) { 1.360 + face.t[i] = obj.vt.size() + face.t[i]; 1.361 + } 1.362 + } 1.363 + 1.364 + // break quads into triangles if needed 1.365 + obj.f.push_back(face); 1.366 + if(face.elem == 4) { 1.367 + face.v[1] = face.v[2]; 1.368 + face.n[1] = face.n[2]; 1.369 + face.t[1] = face.t[2]; 1.370 + 1.371 + face.v[2] = face.v[3]; 1.372 + face.n[2] = face.n[3]; 1.373 + face.t[2] = face.t[3]; 1.374 + 1.375 + obj.f.push_back(face); 1.376 + } 1.377 + break; 1.378 + 1.379 + default: 1.380 + break; // ignore unknown commands 1.381 + } 1.382 + 1.383 + prev_cmd = cmd; 1.384 + } 1.385 + 1.386 + // reached end of file... 1.387 + if(!obj.f.empty()) { 1.388 + Mesh *mesh = cons_mesh(&obj); 1.389 + mesh->matid = matnames[obj.cur_mat]; 1.390 + add_mesh(mesh); 1.391 + obj_added++; 1.392 + } 1.393 + 1.394 + return obj_added > 0; 1.395 +} 1.396 + 1.397 +static Mesh *cons_mesh(obj_file *obj) 1.398 +{ 1.399 + Mesh *mesh; 1.400 + 1.401 + // need at least one of each element 1.402 + bool added_norm = false, added_tc = false; 1.403 + if(obj->vn.empty()) { 1.404 + obj->vn.push_back(Vector3(0, 0, 0)); 1.405 + added_norm = true; 1.406 + } 1.407 + if(obj->vt.empty()) { 1.408 + obj->vt.push_back(Vector3(0, 0, 0)); 1.409 + added_tc = true; 1.410 + } 1.411 + 1.412 + mesh = new Mesh; 1.413 + 1.414 + for(size_t i=0; i<obj->f.size(); i++) { 1.415 + Face face; 1.416 + Vector3 v[3]; 1.417 + 1.418 + for(int j=0; j<3; j++) { 1.419 + obj_face *f = &obj->f[i]; 1.420 + 1.421 + face.v[j].pos[0] = v[j].x = obj->v[f->v[j]].x; 1.422 + face.v[j].pos[1] = v[j].y = obj->v[f->v[j]].y; 1.423 + face.v[j].pos[2] = v[j].z = obj->v[f->v[j]].z; 1.424 + face.v[j].pos[3] = 0.0; 1.425 + 1.426 + int nidx = f->n[j] < 0 ? 0 : f->n[j]; 1.427 + face.v[j].normal[0] = obj->vn[nidx].x; 1.428 + face.v[j].normal[1] = obj->vn[nidx].y; 1.429 + face.v[j].normal[2] = obj->vn[nidx].z; 1.430 + face.v[j].normal[3] = 0.0; 1.431 + 1.432 + int tidx = f->t[j] < 0 ? 0 : f->t[j]; 1.433 + face.v[j].tex[0] = obj->vt[tidx].x; 1.434 + face.v[j].tex[1] = obj->vt[tidx].y; 1.435 + } 1.436 + 1.437 + Vector3 a = v[1] - v[0]; 1.438 + Vector3 b = v[2] - v[0]; 1.439 + Vector3 n = cross(a, b); 1.440 + n.normalize(); 1.441 + 1.442 + face.normal[0] = n.x; 1.443 + face.normal[1] = n.y; 1.444 + face.normal[2] = n.z; 1.445 + face.normal[3] = 0.0; 1.446 + 1.447 + mesh->faces.push_back(face); 1.448 + } 1.449 + 1.450 + if(added_norm) { 1.451 + obj->vn.pop_back(); 1.452 + } 1.453 + if(added_tc) { 1.454 + obj->vt.pop_back(); 1.455 + } 1.456 + 1.457 + return mesh; 1.458 +} 1.459 + 1.460 +static bool read_materials(FILE *fp, vector<obj_mat> *vmtl) 1.461 +{ 1.462 + obj_mat mat; 1.463 + 1.464 + for(;;) { 1.465 + char line[BUF_SZ]; 1.466 + fgets(line, sizeof line, fp); 1.467 + if(feof(fp)) { 1.468 + break; 1.469 + } 1.470 + 1.471 + char *tok; 1.472 + if(!(tok = strtok(line, SEP))) { 1.473 + continue; 1.474 + } 1.475 + 1.476 + int cmd; 1.477 + if((cmd = get_cmd(tok)) == -1) { 1.478 + continue; 1.479 + } 1.480 + 1.481 + switch(cmd) { 1.482 + case CMD_NEWMTL: 1.483 + // add the previous material, and start a new one 1.484 + if(mat.name.length() > 0) { 1.485 + printf("Adding material: %s\n", mat.name.c_str()); 1.486 + vmtl->push_back(mat); 1.487 + mat.reset(); 1.488 + } 1.489 + if((tok = strtok(0, SEP))) { 1.490 + mat.name = tok; 1.491 + } 1.492 + break; 1.493 + 1.494 + case CMD_KA: 1.495 + parse_color(&mat.ambient); 1.496 + break; 1.497 + 1.498 + case CMD_KD: 1.499 + parse_color(&mat.diffuse); 1.500 + break; 1.501 + 1.502 + case CMD_KS: 1.503 + parse_color(&mat.specular); 1.504 + break; 1.505 + 1.506 + case CMD_KR: 1.507 + if((tok = strtok(0, SEP)) && is_float(tok)) { 1.508 + mat.refl = atof(tok); 1.509 + } 1.510 + break; 1.511 + 1.512 + case CMD_NS: 1.513 + if((tok = strtok(0, SEP)) && is_float(tok)) { 1.514 + mat.shininess = atof(tok); 1.515 + } 1.516 + break; 1.517 + 1.518 + case CMD_NI: 1.519 + if((tok = strtok(0, SEP)) && is_float(tok)) { 1.520 + mat.ior = atof(tok); 1.521 + } 1.522 + break; 1.523 + 1.524 + case CMD_D: 1.525 + case CMD_TR: 1.526 + { 1.527 + Vector3 c; 1.528 + if(parse_color(&c)) { 1.529 + mat.alpha = cmd == CMD_D ? c.x : 1.0 - c.x; 1.530 + } 1.531 + } 1.532 + break; 1.533 + 1.534 + case CMD_MAP_KD: 1.535 + mat.tex_dif = parse_map(); 1.536 + break; 1.537 + 1.538 + default: 1.539 + break; 1.540 + } 1.541 + } 1.542 + 1.543 + if(mat.name.length() > 0) { 1.544 + printf("Adding material: %s\n", mat.name.c_str()); 1.545 + vmtl->push_back(mat); 1.546 + } 1.547 + return true; 1.548 +} 1.549 + 1.550 +static int get_cmd(char *str) 1.551 +{ 1.552 + char *s = str; 1.553 + while((*s = toupper(*s))) s++; 1.554 + 1.555 + for(int i=0; cmd_names[i]; i++) { 1.556 + if(strcmp(str, cmd_names[i]) == 0) { 1.557 + return i; 1.558 + } 1.559 + } 1.560 + return CMD_UNK; 1.561 +} 1.562 + 1.563 +static bool is_int(const char *str) 1.564 +{ 1.565 + char *tmp; 1.566 + strtol(str, &tmp, 10); 1.567 + return tmp != str; 1.568 +} 1.569 + 1.570 +static bool is_float(const char *str) 1.571 +{ 1.572 + char *tmp; 1.573 + strtod(str, &tmp); 1.574 + return tmp != str; 1.575 +} 1.576 + 1.577 +static bool parse_vec(Vector3 *vec) 1.578 +{ 1.579 + for(int i=0; i<3; i++) { 1.580 + char *tok; 1.581 + 1.582 + if(!(tok = strtok(0, SEP)) || !is_float(tok)) { 1.583 + if(i < 2) { 1.584 + return false; 1.585 + } 1.586 + vec->z = 0.0; 1.587 + } else { 1.588 + float v = atof(tok); 1.589 + 1.590 + switch(i) { 1.591 + case 0: 1.592 + vec->x = v; 1.593 + break; 1.594 + case 1: 1.595 + vec->y = v; 1.596 + break; 1.597 + case 2: 1.598 + vec->z = v; 1.599 + break; 1.600 + } 1.601 + } 1.602 + } 1.603 + return true; 1.604 +} 1.605 + 1.606 +static bool parse_color(Vector3 *col) 1.607 +{ 1.608 + for(int i=0; i<3; i++) { 1.609 + char *tok; 1.610 + 1.611 + if(!(tok = strtok(0, SEP)) || !is_float(tok)) { 1.612 + col->y = col->z = col->x; 1.613 + return i > 0 ? true : false; 1.614 + } 1.615 + 1.616 + float v = atof(tok); 1.617 + switch(i) { 1.618 + case 0: 1.619 + col->x = v; 1.620 + break; 1.621 + case 1: 1.622 + col->y = v; 1.623 + break; 1.624 + case 2: 1.625 + col->z = v; 1.626 + break; 1.627 + } 1.628 + } 1.629 + return true; 1.630 +} 1.631 + 1.632 +static bool parse_face(obj_face *face) 1.633 +{ 1.634 + char *tok[] = {0, 0, 0, 0}; 1.635 + face->elem = 0; 1.636 + 1.637 + for(int i=0; i<4; i++) { 1.638 + if((!(tok[i] = strtok(0, SEP)) || !is_int(tok[i]))) { 1.639 + if(i < 3) return false; // less than 3 verts? not a polygon 1.640 + } else { 1.641 + face->elem++; 1.642 + } 1.643 + } 1.644 + 1.645 + for(int i=0; i<4; i++) { 1.646 + char *subtok = tok[i]; 1.647 + 1.648 + if(!subtok || !*subtok || !is_int(subtok)) { 1.649 + if(i < 3) { 1.650 + return false; 1.651 + } 1.652 + face->v[i] = INVALID_IDX; 1.653 + } else { 1.654 + face->v[i] = atoi(subtok); 1.655 + if(face->v[i] > 0) face->v[i]--; /* convert to 0-based */ 1.656 + } 1.657 + 1.658 + while(subtok && *subtok && *subtok != '/') { 1.659 + subtok++; 1.660 + } 1.661 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 1.662 + face->t[i] = atoi(subtok); 1.663 + if(face->t[i] > 0) face->t[i]--; /* convert to 0-based */ 1.664 + } else { 1.665 + face->t[i] = INVALID_IDX; 1.666 + } 1.667 + 1.668 + while(subtok && *subtok && *subtok != '/') { 1.669 + subtok++; 1.670 + } 1.671 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 1.672 + face->n[i] = atoi(subtok); 1.673 + if(face->n[i] > 0) face->n[i]--; /* convert to 0-based */ 1.674 + } else { 1.675 + face->n[i] = INVALID_IDX; 1.676 + } 1.677 + } 1.678 + 1.679 + return true; 1.680 +} 1.681 + 1.682 +static const char *parse_map() 1.683 +{ 1.684 + char *tok, *prev = 0; 1.685 + 1.686 + while((tok = strtok(0, SEP))) { 1.687 + prev = tok; 1.688 + } 1.689 + 1.690 + return prev ? prev : ""; 1.691 +} 1.692 + 1.693 +static bool find_file(char *res, int sz, const char *fname, const char *path, const char *mode) 1.694 +{ 1.695 + FILE *fp; 1.696 + const char *beg, *end; 1.697 + int fnamelen = strlen(fname); 1.698 + 1.699 + beg = path; 1.700 + while(beg && *beg) { 1.701 + end = beg; 1.702 + while(*end && *end != ':') { 1.703 + end++; 1.704 + } 1.705 + 1.706 + int res_len = end - beg; 1.707 + char *pathname = (char*)alloca(res_len + fnamelen + 2); 1.708 + memcpy(pathname, beg, res_len); 1.709 + pathname[res_len] = 0; 1.710 + if(res_len) { 1.711 + strcat(pathname, "/"); 1.712 + } 1.713 + strcat(pathname, fname); 1.714 + 1.715 + if((fp = fopen(pathname, mode))) { 1.716 + fclose(fp); 1.717 + strncpy(res, pathname, sz); 1.718 + return true; 1.719 + } 1.720 + 1.721 + beg += res_len; 1.722 + if(*beg == ':') beg++; 1.723 + } 1.724 + return false; 1.725 +} 1.726 + 1.727 +static const char *dirname(const char *str) 1.728 +{ 1.729 + static char buf[PATH_MAX]; 1.730 + 1.731 + if(!str || !*str) { 1.732 + strcpy(buf, "."); 1.733 + } else { 1.734 + strncpy(buf, str, PATH_MAX); 1.735 + char *ptr = strrchr(buf, '/'); 1.736 + 1.737 + if(ptr && *ptr) { 1.738 + *ptr = 0; 1.739 + } else { 1.740 + strcpy(buf, "."); 1.741 + } 1.742 + } 1.743 + return buf; 1.744 +} 1.745 + 1.746 +static Vector3 operator -(const Vector3 &a, const Vector3 &b) 1.747 +{ 1.748 + return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); 1.749 +} 1.750 + 1.751 +static Vector3 cross(const Vector3 &a, const Vector3 &b) 1.752 +{ 1.753 + Vector3 res; 1.754 + res.x = a.y * b.z - a.z * b.y; 1.755 + res.y = a.z * b.x - a.x * b.z; 1.756 + res.z = a.x * b.y - a.y * b.x; 1.757 + return res; 1.758 +}