# HG changeset patch # User John Tsiombikas # Date 1281497435 -3600 # Node ID 6c44e4b1726da7b13bc24286a33c4c74abb13f1e # Parent bd6c2b25f6e7a13bb191ad629ada132b2a76c06f OMG alignment is a bitch diff -r bd6c2b25f6e7 -r 6c44e4b1726d rt.cl --- a/rt.cl Tue Aug 10 07:24:18 2010 +0100 +++ b/rt.cl Wed Aug 11 04:30:35 2010 +0100 @@ -1,10 +1,10 @@ /* vim: set ft=opencl:ts=4:sw=4 */ struct RendInfo { + float4 ambient; int xsz, ysz; int num_faces, num_lights; int max_iter; - float4 ambient; }; struct Vertex { @@ -88,7 +88,7 @@ transform_ray(&ray, xform, invtrans); float4 pixel = (float4)(0, 0, 0, 0); - float4 energy = (float4)(1.0, 1.0, 1.0, 1.0); + float4 energy = (float4)(1.0, 1.0, 1.0, 0.0); int iter = 0; while(iter++ < rinf->max_iter && mean(energy) > MIN_ENERGY) { @@ -136,10 +136,10 @@ float4 vref = reflect(vdir, norm); float diff = fmax(dot(ldir, norm), 0.0f); - dcol += sp->mat.kd * diff * scn->lights[i].color; + dcol += sp->mat.kd * scn->lights[i].color * diff; float spec = powr(fmax(dot(ldir, vref), 0.0f), sp->mat.spow); - scol += sp->mat.ks * spec * scn->lights[i].color; + scol += sp->mat.ks * scn->lights[i].color * spec; } } diff -r bd6c2b25f6e7 -r 6c44e4b1726d src/clray.cc --- a/src/clray.cc Tue Aug 10 07:24:18 2010 +0100 +++ b/src/clray.cc Wed Aug 11 04:30:35 2010 +0100 @@ -9,7 +9,7 @@ #endif #include "rt.h" #include "matrix.h" -#include "mesh.h" +#include "scene.h" void cleanup(); void disp(); @@ -25,7 +25,7 @@ static float cam_theta, cam_phi = 25.0; static float cam_dist = 10.0; -static bool dbg_glrender = true; +static bool dbg_glrender = false; static Scene scn; @@ -128,6 +128,7 @@ dbg_render_gl(&scn); } else { glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); glBegin(GL_QUADS); glColor3f(1, 1, 1); diff -r bd6c2b25f6e7 -r 6c44e4b1726d src/mesh.cc --- a/src/mesh.cc Tue Aug 10 07:24:18 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,755 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mesh.h" - -#ifndef PATH_MAX -#define PATH_MAX 512 -#endif - -using namespace std; - -#define COMMANDS \ - CMD(V), \ - CMD(VN), \ - CMD(VT), \ - CMD(F), \ - CMD(O), \ - CMD(G), \ - CMD(MTLLIB), \ - CMD(USEMTL), \ - CMD(NEWMTL), \ - CMD(KA), \ - CMD(KD), \ - CMD(KS), \ - CMD(KR), \ - CMD(NS), \ - CMD(NI), \ - CMD(D), \ - CMD(TR), \ - CMD(MAP_KD), \ - CMD(MAP_KS), \ - CMD(MAP_NS), \ - CMD(MAP_D), \ - CMD(REFL), \ - CMD(BUMP) - -#define CMD(x) CMD_##x -enum { - COMMANDS, - CMD_UNK -}; -#undef CMD - -#define CMD(x) #x -static const char *cmd_names[] = { - COMMANDS, - 0 -}; -#undef CMD - -struct Vector3 { - float x, y, z; - - Vector3() { x = y = z = 0.0; } - Vector3(float a, float b, float c) { x = a; y = b; z = c; } - - void normalize() { float len = sqrt(x * x + y * y + z * z); x /= len; y /= len; z /= len; } -}; - -struct Vector2 { - float x, y; - - Vector2() { x = y = 0.0; } - Vector2(float a, float b) { x = a; y = b; } -}; - -struct obj_face { - int elem; - int v[4], n[4], t[4]; -}; - -struct obj_file { - string cur_obj, cur_mat; - vector v, vn, vt; - vector f; -}; - -struct obj_mat { - string name; // newmtl - Vector3 ambient, diffuse, specular; // Ka, Kd, Ks - float shininess; // Ns - float ior; // Ni - float alpha; // d, Tr - float refl; // Kr (my extesnsion) - - string tex_dif, tex_spec, tex_shin, tex_alpha; // map_Kd, map_Ks, map_Ns, map_d - string tex_refl; // refl -type sphere|cube file - string tex_bump; // bump - - obj_mat() { reset(); } - - void reset() { - ambient = diffuse = Vector3(0.5, 0.5, 0.5); - specular = Vector3(0.0, 0.0, 0.0); - name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = ""; - shininess = 0; - ior = alpha = 1; - refl = 0.0; - } -}; - -static bool read_materials(FILE *fp, vector *vmtl); -static Mesh *cons_mesh(obj_file *obj); - -static int get_cmd(char *str); -static bool is_int(const char *str); -static bool is_float(const char *str); -static bool parse_vec(Vector3 *vec); -static bool parse_color(Vector3 *col); -static bool parse_face(obj_face *face); -static const char *parse_map(); - -static bool find_file(char *res, int sz, const char *fname, const char *path = ".", const char *mode = "rb"); -static const char *dirname(const char *str); - -static Vector3 operator -(const Vector3 &a, const Vector3 &b); -static Vector3 cross(const Vector3 &a, const Vector3 &b); - -static map matnames; - - -#define FEQ(a, b) (fabs((a) - (b)) < 1e-8) -bool Face::operator ==(const Face &f) const -{ - for(int i=0; i<3; i++) { - for(int j=0; j<3; j++) { - if(!FEQ(v[i].pos[j], f.v[i].pos[j])) { - return false; - } - if(!FEQ(v[i].normal[j], f.v[i].normal[j])) { - return false; - } - } - if(!FEQ(normal[i], f.normal[i])) { - return false; - } - } - return true; -} - -bool Scene::add_mesh(Mesh *m) -{ - // make sure triangles have material ids - for(size_t i=0; ifaces.size(); i++) { - m->faces[i].matid = m->matid; - } - meshes.push_back(m); - return true; -} - -int Scene::get_num_meshes() const -{ - return (int)meshes.size(); -} - -int Scene::get_num_faces() const -{ - int num_faces = 0; - for(size_t i=0; ifaces.size(); - } - return num_faces; -} - -int Scene::get_num_materials() const -{ - return (int)matlib.size(); -} - -Material *Scene::get_materials() -{ - if(matlib.empty()) { - return 0; - } - return &matlib[0]; -} - -const Material *Scene::get_materials() const -{ - if(matlib.empty()) { - return 0; - } - return &matlib[0]; -} - - -#define INVALID_IDX INT_MIN - -#define SEP " \t\n\r\v" -#define BUF_SZ 512 - -bool Scene::load(const char *fname) -{ - FILE *fp; - - if(!(fp = fopen(fname, "rb"))) { - fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno)); - return false; - } - - bool res = load(fp); - fclose(fp); - return res; -} - -bool Scene::load(FILE *fp) -{ - static int seq; - char cur_name[16]; - - obj_file obj; - - sprintf(cur_name, "default%02d.obj", seq++); - obj.cur_obj = cur_name; - - int prev_cmd = 0, obj_added = 0; - for(;;) { - Vector3 vec; - obj_face face; - - char line[BUF_SZ]; - fgets(line, sizeof line, fp); - if(feof(fp)) { - break; - } - - char *tok; - if(!(tok = strtok(line, SEP))) { - continue; // ignore empty lines - } - - int cmd; - if((cmd = get_cmd(tok)) == -1) { - continue; // ignore unknown commands ... - } - - switch(cmd) { - case CMD_V: - if(!parse_vec(&vec)) { - continue; - } - obj.v.push_back(vec); - break; - - case CMD_VN: - if(!parse_vec(&vec)) { - continue; - } - obj.vn.push_back(vec); - break; - - case CMD_VT: - if(!parse_vec(&vec)) { - continue; - } - vec.y = 1.0 - vec.y; - obj.vt.push_back(vec); - break; - - case CMD_O: - case CMD_G: - if(prev_cmd == CMD_O || prev_cmd == CMD_G) { - break; // just in case we've got both of them in a row - } - /* if we have any previous data, group them up, add the object - * and continue with the new one... - */ - if(!obj.f.empty()) { - Mesh *mesh = cons_mesh(&obj); - mesh->matid = matnames[obj.cur_mat]; - add_mesh(mesh); - obj_added++; - - obj.f.clear(); // clean the face list - } - if((tok = strtok(0, SEP))) { - obj.cur_obj = tok; - } else { - sprintf(cur_name, "default%02d.obj", seq++); - obj.cur_obj = cur_name; - } - break; - - case CMD_MTLLIB: - if((tok = strtok(0, SEP))) { - char path[PATH_MAX]; - - sprintf(path, ".:%s", dirname(tok)); - if(!find_file(path, PATH_MAX, tok, path)) { - fprintf(stderr, "material library not found: %s\n", tok); - continue; - } - - FILE *mfile; - if(!(mfile = fopen(path, "rb"))) { - fprintf(stderr, "failed to open material library: %s\n", path); - continue; - } - - // load all materials of the mtl file into a vector - vector vmtl; - if(!read_materials(mfile, &vmtl)) { - continue; - } - fclose(mfile); - - // and add them all to the scene - for(size_t i=0; imatid = matnames[obj.cur_mat]; - add_mesh(mesh); - obj_added++; - } - - return obj_added > 0; -} - -static Mesh *cons_mesh(obj_file *obj) -{ - Mesh *mesh; - - // need at least one of each element - bool added_norm = false, added_tc = false; - if(obj->vn.empty()) { - obj->vn.push_back(Vector3(0, 0, 0)); - added_norm = true; - } - if(obj->vt.empty()) { - obj->vt.push_back(Vector3(0, 0, 0)); - added_tc = true; - } - - mesh = new Mesh; - - for(size_t i=0; if.size(); i++) { - Face face; - Vector3 v[3]; - - for(int j=0; j<3; j++) { - obj_face *f = &obj->f[i]; - - face.v[j].pos[0] = v[j].x = obj->v[f->v[j]].x; - face.v[j].pos[1] = v[j].y = obj->v[f->v[j]].y; - face.v[j].pos[2] = v[j].z = obj->v[f->v[j]].z; - face.v[j].pos[3] = 0.0; - - int nidx = f->n[j] < 0 ? 0 : f->n[j]; - face.v[j].normal[0] = obj->vn[nidx].x; - face.v[j].normal[1] = obj->vn[nidx].y; - face.v[j].normal[2] = obj->vn[nidx].z; - face.v[j].normal[3] = 0.0; - - int tidx = f->t[j] < 0 ? 0 : f->t[j]; - face.v[j].tex[0] = obj->vt[tidx].x; - face.v[j].tex[1] = obj->vt[tidx].y; - } - - Vector3 a = v[1] - v[0]; - Vector3 b = v[2] - v[0]; - Vector3 n = cross(a, b); - n.normalize(); - - face.normal[0] = n.x; - face.normal[1] = n.y; - face.normal[2] = n.z; - face.normal[3] = 0.0; - - mesh->faces.push_back(face); - } - - if(added_norm) { - obj->vn.pop_back(); - } - if(added_tc) { - obj->vt.pop_back(); - } - - return mesh; -} - -static bool read_materials(FILE *fp, vector *vmtl) -{ - obj_mat mat; - - for(;;) { - char line[BUF_SZ]; - fgets(line, sizeof line, fp); - if(feof(fp)) { - break; - } - - char *tok; - if(!(tok = strtok(line, SEP))) { - continue; - } - - int cmd; - if((cmd = get_cmd(tok)) == -1) { - continue; - } - - switch(cmd) { - case CMD_NEWMTL: - // add the previous material, and start a new one - if(mat.name.length() > 0) { - printf("Adding material: %s\n", mat.name.c_str()); - vmtl->push_back(mat); - mat.reset(); - } - if((tok = strtok(0, SEP))) { - mat.name = tok; - } - break; - - case CMD_KA: - parse_color(&mat.ambient); - break; - - case CMD_KD: - parse_color(&mat.diffuse); - break; - - case CMD_KS: - parse_color(&mat.specular); - break; - - case CMD_KR: - if((tok = strtok(0, SEP)) && is_float(tok)) { - mat.refl = atof(tok); - } - break; - - case CMD_NS: - if((tok = strtok(0, SEP)) && is_float(tok)) { - mat.shininess = atof(tok); - } - break; - - case CMD_NI: - if((tok = strtok(0, SEP)) && is_float(tok)) { - mat.ior = atof(tok); - } - break; - - case CMD_D: - case CMD_TR: - { - Vector3 c; - if(parse_color(&c)) { - mat.alpha = cmd == CMD_D ? c.x : 1.0 - c.x; - } - } - break; - - case CMD_MAP_KD: - mat.tex_dif = parse_map(); - break; - - default: - break; - } - } - - if(mat.name.length() > 0) { - printf("Adding material: %s\n", mat.name.c_str()); - vmtl->push_back(mat); - } - return true; -} - -static int get_cmd(char *str) -{ - char *s = str; - while((*s = toupper(*s))) s++; - - for(int i=0; cmd_names[i]; i++) { - if(strcmp(str, cmd_names[i]) == 0) { - return i; - } - } - return CMD_UNK; -} - -static bool is_int(const char *str) -{ - char *tmp; - strtol(str, &tmp, 10); - return tmp != str; -} - -static bool is_float(const char *str) -{ - char *tmp; - strtod(str, &tmp); - return tmp != str; -} - -static bool parse_vec(Vector3 *vec) -{ - for(int i=0; i<3; i++) { - char *tok; - - if(!(tok = strtok(0, SEP)) || !is_float(tok)) { - if(i < 2) { - return false; - } - vec->z = 0.0; - } else { - float v = atof(tok); - - switch(i) { - case 0: - vec->x = v; - break; - case 1: - vec->y = v; - break; - case 2: - vec->z = v; - break; - } - } - } - return true; -} - -static bool parse_color(Vector3 *col) -{ - for(int i=0; i<3; i++) { - char *tok; - - if(!(tok = strtok(0, SEP)) || !is_float(tok)) { - col->y = col->z = col->x; - return i > 0 ? true : false; - } - - float v = atof(tok); - switch(i) { - case 0: - col->x = v; - break; - case 1: - col->y = v; - break; - case 2: - col->z = v; - break; - } - } - return true; -} - -static bool parse_face(obj_face *face) -{ - char *tok[] = {0, 0, 0, 0}; - face->elem = 0; - - for(int i=0; i<4; i++) { - if((!(tok[i] = strtok(0, SEP)) || !is_int(tok[i]))) { - if(i < 3) return false; // less than 3 verts? not a polygon - } else { - face->elem++; - } - } - - for(int i=0; i<4; i++) { - char *subtok = tok[i]; - - if(!subtok || !*subtok || !is_int(subtok)) { - if(i < 3) { - return false; - } - face->v[i] = INVALID_IDX; - } else { - face->v[i] = atoi(subtok); - if(face->v[i] > 0) face->v[i]--; /* convert to 0-based */ - } - - while(subtok && *subtok && *subtok != '/') { - subtok++; - } - if(subtok && *subtok && *++subtok && is_int(subtok)) { - face->t[i] = atoi(subtok); - if(face->t[i] > 0) face->t[i]--; /* convert to 0-based */ - } else { - face->t[i] = INVALID_IDX; - } - - while(subtok && *subtok && *subtok != '/') { - subtok++; - } - if(subtok && *subtok && *++subtok && is_int(subtok)) { - face->n[i] = atoi(subtok); - if(face->n[i] > 0) face->n[i]--; /* convert to 0-based */ - } else { - face->n[i] = INVALID_IDX; - } - } - - return true; -} - -static const char *parse_map() -{ - char *tok, *prev = 0; - - while((tok = strtok(0, SEP))) { - prev = tok; - } - - return prev ? prev : ""; -} - -static bool find_file(char *res, int sz, const char *fname, const char *path, const char *mode) -{ - FILE *fp; - const char *beg, *end; - int fnamelen = strlen(fname); - - beg = path; - while(beg && *beg) { - end = beg; - while(*end && *end != ':') { - end++; - } - - int res_len = end - beg; - char *pathname = (char*)alloca(res_len + fnamelen + 2); - memcpy(pathname, beg, res_len); - pathname[res_len] = 0; - if(res_len) { - strcat(pathname, "/"); - } - strcat(pathname, fname); - - if((fp = fopen(pathname, mode))) { - fclose(fp); - strncpy(res, pathname, sz); - return true; - } - - beg += res_len; - if(*beg == ':') beg++; - } - return false; -} - -static const char *dirname(const char *str) -{ - static char buf[PATH_MAX]; - - if(!str || !*str) { - strcpy(buf, "."); - } else { - strncpy(buf, str, PATH_MAX); - char *ptr = strrchr(buf, '/'); - - if(ptr && *ptr) { - *ptr = 0; - } else { - strcpy(buf, "."); - } - } - return buf; -} - -static Vector3 operator -(const Vector3 &a, const Vector3 &b) -{ - return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); -} - -static Vector3 cross(const Vector3 &a, const Vector3 &b) -{ - Vector3 res; - res.x = a.y * b.z - a.z * b.y; - res.y = a.z * b.x - a.x * b.z; - res.z = a.x * b.y - a.y * b.x; - return res; -} diff -r bd6c2b25f6e7 -r 6c44e4b1726d src/mesh.h --- a/src/mesh.h Tue Aug 10 07:24:18 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#ifndef MESH_H_ -#define MESH_H_ - -#include - -struct Vertex { - float pos[4]; - float normal[4]; - float tex[4]; - float padding[4]; -}; - -struct Face { - Vertex v[3]; - float normal[4]; - int matid; - int padding[3]; - - bool operator ==(const Face &f) const; -}; - -struct Material { - float kd[4], ks[4]; - float kr, kt; - float spow; - float padding; -}; - -struct Mesh { - std::vector faces; - int matid; -}; - -class Scene { -public: - std::vector meshes; - std::vector matlib; - - bool add_mesh(Mesh *m); - int get_num_meshes() const; - int get_num_materials() const; - int get_num_faces() const; - - Material *get_materials(); - const Material *get_materials() const; - - bool load(const char *fname); - bool load(FILE *fp); -}; - -#endif /* MESH_H_ */ diff -r bd6c2b25f6e7 -r 6c44e4b1726d src/rt.cc --- a/src/rt.cc Tue Aug 10 07:24:18 2010 +0100 +++ b/src/rt.cc Wed Aug 11 04:30:35 2010 +0100 @@ -4,7 +4,7 @@ #include #include "ogl.h" #include "ocl.h" -#include "mesh.h" +#include "scene.h" // kernel arguments enum { @@ -21,10 +21,10 @@ }; struct RendInfo { + float ambient[4]; int xsz, ysz; int num_faces, num_lights; int max_iter; - float ambient[4]; }; struct Ray { @@ -44,7 +44,7 @@ static int global_size; static Light lightlist[] = { - {{-8, 15, -18, 0}, {1, 1, 1, 1}} + {{-8, 15, 18, 0}, {1, 1, 1, 1}} }; @@ -54,7 +54,7 @@ bool init_renderer(int xsz, int ysz, Scene *scn) { // render info - rinf.ambient[0] = rinf.ambient[1] = rinf.ambient[2] = 0.075; + rinf.ambient[0] = rinf.ambient[1] = rinf.ambient[2] = 0.0; rinf.ambient[3] = 0.0; rinf.xsz = xsz; @@ -115,13 +115,9 @@ bool render() { - printf("Running kernel... "); - fflush(stdout); if(!prog->run(1, global_size)) { return false; } - printf("done\n"); - CLMemBuffer *mbuf = prog->get_arg_buffer(KARG_FRAMEBUFFER); void *fb = map_mem_buffer(mbuf, MAP_RD); @@ -130,6 +126,12 @@ return false; } + static int foo = 0; + if(!foo++) { + bool write_ppm(const char *fname, float *fb, int xsz, int ysz); + write_ppm("foo.ppm", (float*)fb, rinf.xsz, rinf.ysz); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rinf.xsz, rinf.ysz, GL_RGBA, GL_FLOAT, fb); unmap_mem_buffer(mbuf); return true; @@ -148,7 +150,7 @@ void dbg_render_gl(Scene *scn) { - glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT); + glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_BIT); for(int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include "scene.h" + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +using namespace std; + +#define COMMANDS \ + CMD(V), \ + CMD(VN), \ + CMD(VT), \ + CMD(F), \ + CMD(O), \ + CMD(G), \ + CMD(MTLLIB), \ + CMD(USEMTL), \ + CMD(NEWMTL), \ + CMD(KA), \ + CMD(KD), \ + CMD(KS), \ + CMD(KR), \ + CMD(NS), \ + CMD(NI), \ + CMD(D), \ + CMD(TR), \ + CMD(MAP_KD), \ + CMD(MAP_KS), \ + CMD(MAP_NS), \ + CMD(MAP_D), \ + CMD(REFL), \ + CMD(BUMP) + +#define CMD(x) CMD_##x +enum { + COMMANDS, + CMD_UNK +}; +#undef CMD + +#define CMD(x) #x +static const char *cmd_names[] = { + COMMANDS, + 0 +}; +#undef CMD + +struct Vector3 { + float x, y, z; + + Vector3() { x = y = z = 0.0; } + Vector3(float a, float b, float c) { x = a; y = b; z = c; } + + void normalize() { float len = sqrt(x * x + y * y + z * z); x /= len; y /= len; z /= len; } +}; + +struct Vector2 { + float x, y; + + Vector2() { x = y = 0.0; } + Vector2(float a, float b) { x = a; y = b; } +}; + +struct obj_face { + int elem; + int v[4], n[4], t[4]; +}; + +struct obj_file { + string cur_obj, cur_mat; + vector v, vn, vt; + vector f; +}; + +struct obj_mat { + string name; // newmtl + Vector3 ambient, diffuse, specular; // Ka, Kd, Ks + float shininess; // Ns + float ior; // Ni + float alpha; // d, Tr + float refl; // Kr (my extesnsion) + + string tex_dif, tex_spec, tex_shin, tex_alpha; // map_Kd, map_Ks, map_Ns, map_d + string tex_refl; // refl -type sphere|cube file + string tex_bump; // bump + + obj_mat() { reset(); } + + void reset() { + ambient = diffuse = Vector3(0.5, 0.5, 0.5); + specular = Vector3(0.0, 0.0, 0.0); + name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = ""; + shininess = 0; + ior = alpha = 1; + refl = 0.0; + } +}; + +static bool read_materials(FILE *fp, vector *vmtl); +static Mesh *cons_mesh(obj_file *obj); + +static int get_cmd(char *str); +static bool is_int(const char *str); +static bool is_float(const char *str); +static bool parse_vec(Vector3 *vec); +static bool parse_color(Vector3 *col); +static bool parse_face(obj_face *face); +static const char *parse_map(); + +static bool find_file(char *res, int sz, const char *fname, const char *path = ".", const char *mode = "rb"); +static const char *dirname(const char *str); + +static Vector3 operator -(const Vector3 &a, const Vector3 &b); +static Vector3 cross(const Vector3 &a, const Vector3 &b); + +static map matnames; + + +#define FEQ(a, b) (fabs((a) - (b)) < 1e-8) +bool Face::operator ==(const Face &f) const +{ + for(int i=0; i<3; i++) { + for(int j=0; j<3; j++) { + if(!FEQ(v[i].pos[j], f.v[i].pos[j])) { + return false; + } + if(!FEQ(v[i].normal[j], f.v[i].normal[j])) { + return false; + } + } + if(!FEQ(normal[i], f.normal[i])) { + return false; + } + } + return true; +} + +bool Scene::add_mesh(Mesh *m) +{ + // make sure triangles have material ids + for(size_t i=0; ifaces.size(); i++) { + m->faces[i].matid = m->matid; + } + meshes.push_back(m); + return true; +} + +int Scene::get_num_meshes() const +{ + return (int)meshes.size(); +} + +int Scene::get_num_faces() const +{ + int num_faces = 0; + for(size_t i=0; ifaces.size(); + } + return num_faces; +} + +int Scene::get_num_materials() const +{ + return (int)matlib.size(); +} + +Material *Scene::get_materials() +{ + if(matlib.empty()) { + return 0; + } + return &matlib[0]; +} + +const Material *Scene::get_materials() const +{ + if(matlib.empty()) { + return 0; + } + return &matlib[0]; +} + + +#define INVALID_IDX INT_MIN + +#define SEP " \t\n\r\v" +#define BUF_SZ 512 + +bool Scene::load(const char *fname) +{ + FILE *fp; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno)); + return false; + } + + bool res = load(fp); + fclose(fp); + return res; +} + +bool Scene::load(FILE *fp) +{ + static int seq; + char cur_name[16]; + + obj_file obj; + + sprintf(cur_name, "default%02d.obj", seq++); + obj.cur_obj = cur_name; + + int prev_cmd = 0, obj_added = 0; + for(;;) { + Vector3 vec; + obj_face face; + + char line[BUF_SZ]; + fgets(line, sizeof line, fp); + if(feof(fp)) { + break; + } + + char *tok; + if(!(tok = strtok(line, SEP))) { + continue; // ignore empty lines + } + + int cmd; + if((cmd = get_cmd(tok)) == -1) { + continue; // ignore unknown commands ... + } + + switch(cmd) { + case CMD_V: + if(!parse_vec(&vec)) { + continue; + } + obj.v.push_back(vec); + break; + + case CMD_VN: + if(!parse_vec(&vec)) { + continue; + } + obj.vn.push_back(vec); + break; + + case CMD_VT: + if(!parse_vec(&vec)) { + continue; + } + vec.y = 1.0 - vec.y; + obj.vt.push_back(vec); + break; + + case CMD_O: + case CMD_G: + if(prev_cmd == CMD_O || prev_cmd == CMD_G) { + break; // just in case we've got both of them in a row + } + /* if we have any previous data, group them up, add the object + * and continue with the new one... + */ + if(!obj.f.empty()) { + Mesh *mesh = cons_mesh(&obj); + mesh->matid = matnames[obj.cur_mat]; + add_mesh(mesh); + obj_added++; + + obj.f.clear(); // clean the face list + } + if((tok = strtok(0, SEP))) { + obj.cur_obj = tok; + } else { + sprintf(cur_name, "default%02d.obj", seq++); + obj.cur_obj = cur_name; + } + break; + + case CMD_MTLLIB: + if((tok = strtok(0, SEP))) { + char path[PATH_MAX]; + + sprintf(path, ".:%s", dirname(tok)); + if(!find_file(path, PATH_MAX, tok, path)) { + fprintf(stderr, "material library not found: %s\n", tok); + continue; + } + + FILE *mfile; + if(!(mfile = fopen(path, "rb"))) { + fprintf(stderr, "failed to open material library: %s\n", path); + continue; + } + + // load all materials of the mtl file into a vector + vector vmtl; + if(!read_materials(mfile, &vmtl)) { + continue; + } + fclose(mfile); + + // and add them all to the scene + for(size_t i=0; imatid = matnames[obj.cur_mat]; + add_mesh(mesh); + obj_added++; + } + + return obj_added > 0; +} + +static Mesh *cons_mesh(obj_file *obj) +{ + Mesh *mesh; + + // need at least one of each element + bool added_norm = false, added_tc = false; + if(obj->vn.empty()) { + obj->vn.push_back(Vector3(0, 0, 0)); + added_norm = true; + } + if(obj->vt.empty()) { + obj->vt.push_back(Vector3(0, 0, 0)); + added_tc = true; + } + + mesh = new Mesh; + + for(size_t i=0; if.size(); i++) { + Face face; + Vector3 v[3]; + + for(int j=0; j<3; j++) { + obj_face *f = &obj->f[i]; + + face.v[j].pos[0] = v[j].x = obj->v[f->v[j]].x; + face.v[j].pos[1] = v[j].y = obj->v[f->v[j]].y; + face.v[j].pos[2] = v[j].z = obj->v[f->v[j]].z; + face.v[j].pos[3] = 0.0; + + int nidx = f->n[j] < 0 ? 0 : f->n[j]; + face.v[j].normal[0] = obj->vn[nidx].x; + face.v[j].normal[1] = obj->vn[nidx].y; + face.v[j].normal[2] = obj->vn[nidx].z; + face.v[j].normal[3] = 0.0; + + int tidx = f->t[j] < 0 ? 0 : f->t[j]; + face.v[j].tex[0] = obj->vt[tidx].x; + face.v[j].tex[1] = obj->vt[tidx].y; + } + + Vector3 a = v[1] - v[0]; + Vector3 b = v[2] - v[0]; + Vector3 n = cross(a, b); + n.normalize(); + + face.normal[0] = n.x; + face.normal[1] = n.y; + face.normal[2] = n.z; + face.normal[3] = 0.0; + + mesh->faces.push_back(face); + } + + if(added_norm) { + obj->vn.pop_back(); + } + if(added_tc) { + obj->vt.pop_back(); + } + + return mesh; +} + +static bool read_materials(FILE *fp, vector *vmtl) +{ + obj_mat mat; + + for(;;) { + char line[BUF_SZ]; + fgets(line, sizeof line, fp); + if(feof(fp)) { + break; + } + + char *tok; + if(!(tok = strtok(line, SEP))) { + continue; + } + + int cmd; + if((cmd = get_cmd(tok)) == -1) { + continue; + } + + switch(cmd) { + case CMD_NEWMTL: + // add the previous material, and start a new one + if(mat.name.length() > 0) { + printf("Adding material: %s\n", mat.name.c_str()); + vmtl->push_back(mat); + mat.reset(); + } + if((tok = strtok(0, SEP))) { + mat.name = tok; + } + break; + + case CMD_KA: + parse_color(&mat.ambient); + break; + + case CMD_KD: + parse_color(&mat.diffuse); + break; + + case CMD_KS: + parse_color(&mat.specular); + break; + + case CMD_KR: + if((tok = strtok(0, SEP)) && is_float(tok)) { + mat.refl = atof(tok); + } + break; + + case CMD_NS: + if((tok = strtok(0, SEP)) && is_float(tok)) { + mat.shininess = atof(tok); + } + break; + + case CMD_NI: + if((tok = strtok(0, SEP)) && is_float(tok)) { + mat.ior = atof(tok); + } + break; + + case CMD_D: + case CMD_TR: + { + Vector3 c; + if(parse_color(&c)) { + mat.alpha = cmd == CMD_D ? c.x : 1.0 - c.x; + } + } + break; + + case CMD_MAP_KD: + mat.tex_dif = parse_map(); + break; + + default: + break; + } + } + + if(mat.name.length() > 0) { + printf("Adding material: %s\n", mat.name.c_str()); + vmtl->push_back(mat); + } + return true; +} + +static int get_cmd(char *str) +{ + char *s = str; + while((*s = toupper(*s))) s++; + + for(int i=0; cmd_names[i]; i++) { + if(strcmp(str, cmd_names[i]) == 0) { + return i; + } + } + return CMD_UNK; +} + +static bool is_int(const char *str) +{ + char *tmp; + strtol(str, &tmp, 10); + return tmp != str; +} + +static bool is_float(const char *str) +{ + char *tmp; + strtod(str, &tmp); + return tmp != str; +} + +static bool parse_vec(Vector3 *vec) +{ + for(int i=0; i<3; i++) { + char *tok; + + if(!(tok = strtok(0, SEP)) || !is_float(tok)) { + if(i < 2) { + return false; + } + vec->z = 0.0; + } else { + float v = atof(tok); + + switch(i) { + case 0: + vec->x = v; + break; + case 1: + vec->y = v; + break; + case 2: + vec->z = v; + break; + } + } + } + return true; +} + +static bool parse_color(Vector3 *col) +{ + for(int i=0; i<3; i++) { + char *tok; + + if(!(tok = strtok(0, SEP)) || !is_float(tok)) { + col->y = col->z = col->x; + return i > 0 ? true : false; + } + + float v = atof(tok); + switch(i) { + case 0: + col->x = v; + break; + case 1: + col->y = v; + break; + case 2: + col->z = v; + break; + } + } + return true; +} + +static bool parse_face(obj_face *face) +{ + char *tok[] = {0, 0, 0, 0}; + face->elem = 0; + + for(int i=0; i<4; i++) { + if((!(tok[i] = strtok(0, SEP)) || !is_int(tok[i]))) { + if(i < 3) return false; // less than 3 verts? not a polygon + } else { + face->elem++; + } + } + + for(int i=0; i<4; i++) { + char *subtok = tok[i]; + + if(!subtok || !*subtok || !is_int(subtok)) { + if(i < 3) { + return false; + } + face->v[i] = INVALID_IDX; + } else { + face->v[i] = atoi(subtok); + if(face->v[i] > 0) face->v[i]--; /* convert to 0-based */ + } + + while(subtok && *subtok && *subtok != '/') { + subtok++; + } + if(subtok && *subtok && *++subtok && is_int(subtok)) { + face->t[i] = atoi(subtok); + if(face->t[i] > 0) face->t[i]--; /* convert to 0-based */ + } else { + face->t[i] = INVALID_IDX; + } + + while(subtok && *subtok && *subtok != '/') { + subtok++; + } + if(subtok && *subtok && *++subtok && is_int(subtok)) { + face->n[i] = atoi(subtok); + if(face->n[i] > 0) face->n[i]--; /* convert to 0-based */ + } else { + face->n[i] = INVALID_IDX; + } + } + + return true; +} + +static const char *parse_map() +{ + char *tok, *prev = 0; + + while((tok = strtok(0, SEP))) { + prev = tok; + } + + return prev ? prev : ""; +} + +static bool find_file(char *res, int sz, const char *fname, const char *path, const char *mode) +{ + FILE *fp; + const char *beg, *end; + int fnamelen = strlen(fname); + + beg = path; + while(beg && *beg) { + end = beg; + while(*end && *end != ':') { + end++; + } + + int res_len = end - beg; + char *pathname = (char*)alloca(res_len + fnamelen + 2); + memcpy(pathname, beg, res_len); + pathname[res_len] = 0; + if(res_len) { + strcat(pathname, "/"); + } + strcat(pathname, fname); + + if((fp = fopen(pathname, mode))) { + fclose(fp); + strncpy(res, pathname, sz); + return true; + } + + beg += res_len; + if(*beg == ':') beg++; + } + return false; +} + +static const char *dirname(const char *str) +{ + static char buf[PATH_MAX]; + + if(!str || !*str) { + strcpy(buf, "."); + } else { + strncpy(buf, str, PATH_MAX); + char *ptr = strrchr(buf, '/'); + + if(ptr && *ptr) { + *ptr = 0; + } else { + strcpy(buf, "."); + } + } + return buf; +} + +static Vector3 operator -(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +static Vector3 cross(const Vector3 &a, const Vector3 &b) +{ + Vector3 res; + res.x = a.y * b.z - a.z * b.y; + res.y = a.z * b.x - a.x * b.z; + res.z = a.x * b.y - a.y * b.x; + return res; +} diff -r bd6c2b25f6e7 -r 6c44e4b1726d src/scene.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scene.h Wed Aug 11 04:30:35 2010 +0100 @@ -0,0 +1,71 @@ +#ifndef MESH_H_ +#define MESH_H_ + +#include + +struct Vertex { + float pos[4]; + float normal[4]; + float tex[4]; + float padding[4]; +}; + +struct Face { + Vertex v[3]; + float normal[4]; + int matid; + int padding[3]; + + bool operator ==(const Face &f) const; +}; + +struct Material { + float kd[4], ks[4]; + float kr, kt; + float spow; + float padding; +}; + +struct Mesh { + std::vector faces; + int matid; +}; + +/*enum { + KDAXIS_X, + KDAXIS_Y, + KDAXIS_Z +}; + +#define KDCLEAR(node) ((node)->axis = -1) +#define KDUSED(node) ((node)->axis >= 0) +#define KDPARENT(x) ((x) >> 1) +#define KDLEFT(x) ((x) << 1) +#define KDRIGHT(x) (((x) << 1) + 1) + +struct KDNode { + int axis; + float pt; +};*/ + +class Scene { +public: + std::vector meshes; + std::vector matlib; + //std::vector kdtree; + + bool add_mesh(Mesh *m); + int get_num_meshes() const; + int get_num_materials() const; + int get_num_faces() const; + + Material *get_materials(); + const Material *get_materials() const; + + bool load(const char *fname); + bool load(FILE *fp); + + //void build_kdtree(); +}; + +#endif /* MESH_H_ */