# HG changeset patch # User John Tsiombikas # Date 1405553719 -10800 # Node ID f9274bebe55e3f8d35a5730fe01e2a8080cc2fb4 # Parent 48dce4ee485014b33897f4b6725ea708c903075c adding 3d graphics stuff diff -r 48dce4ee4850 -r f9274bebe55e src/material.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/material.cc Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,20 @@ +#include +#include "material.h" + +Material::Material() + : color(1, 1, 1), specular(0, 0, 0) +{ + shininess = 1.0; + alpha = 1.0; +} + +void Material::setup() const +{ + float col[] = {color.x, color.y, color.z, alpha}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); + + float spec[] = {specular.x, specular.y, specular.z, 1.0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); + + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess > 128 ? 128 : shininess); +} diff -r 48dce4ee4850 -r f9274bebe55e src/material.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/material.h Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,19 @@ +#ifndef MATERIAL_H_ +#define MATERIAL_H_ + +#include "vmath.h" + +class Material { +public: + Vector3 ambient; + Vector3 diffuse; + Vector3 specular; + float shininess; + float alpha; + + Material(); + + void setup() const; +}; + +#endif // MATERIAL_H_ diff -r 48dce4ee4850 -r f9274bebe55e src/mesh.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/mesh.cc Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,101 @@ +#include +#include +#include +#include "mesh.h" + +#define ALL_VALID 0xffffffff + +Mesh::Mesh() +{ + buf_valid = ALL_VALID; + + for(int i=0; imesh = mesh; +} + +Mesh *Object::get_mesh() const +{ + return mesh; +} + +void Object::render() const +{ + if(!mesh) return; + + mtl.setup(); + mesh->draw(); +} diff -r 48dce4ee4850 -r f9274bebe55e src/object.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/object.h Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,22 @@ +#ifndef OBJECT_H_ +#define OBJECT_H_ + +#include "mesh.h" +#include "material.h" + +class Object { +private: + Mesh *mesh; + +public: + Material mtl; + + Object(); + + void set_mesh(Mesh *mesh); + Mesh *get_mesh() const; + + void render() const; +}; + +#endif // OBJECT_H_ diff -r 48dce4ee4850 -r f9274bebe55e src/objfile.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objfile.cc Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,542 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scene.h" + +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(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 ObjFace { + int elem; + int v[4], n[4], t[4]; +}; + +struct ObjFile { + string cur_obj, cur_mat; + vector v, vn; + vector vt; + vector f; +}; + +typedef Vector3 Color; + +struct ObjMat { + string name; // newmtl + Color ambient, diffuse, specular; // Ka, Kd, Ks + float shininess; // Ns + float ior; // Ni + float alpha; // d, Tr + + 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 + + ObjMat() { reset(); } + + void reset() { + ambient = diffuse = Color(0.5, 0.5, 0.5); + specular = Color(0.0, 0.0, 0.0); + name = tex_dif = tex_spec = tex_shin = tex_alpha = tex_refl = tex_bump = ""; + shininess = 0; + ior = alpha = 1; + } +}; + +static bool read_materials(FILE *fp, vector *vmtl); +static Object *cons_object(ObjFile *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(Color *col); +static bool parse_face(ObjFace *face); +static const char *parse_map(); + + +static map matlib; + + +#define INVALID_IDX INT_MIN + +#define SEP " \t\n\r\v" +#define BUF_SZ 512 +bool Scene::load_obj(FILE *fp) +{ + static int seq; + char cur_name[16]; + stringstream sstr; + + ObjFile obj; + + sprintf(cur_name, "default%02d.obj", seq++); + obj.cur_obj = cur_name; + + int prev_cmd = 0, obj_added = 0; + for(;;) { + Vector3 vec; + ObjFace 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(Vector2(vec.x, vec.y)); + 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()) { + Object *robj = cons_object(&obj); + robj->mtl = matlib[obj.cur_mat]; + add_object(robj); + 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))) { + FILE *mfile; + if(!(mfile = fopen(tok, "rb"))) { + fprintf(stderr, "failed to open material library: %s\n", tok); + 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; imtl = matlib[obj.cur_mat]; + add_object(robj); + obj_added++; + } + + return obj_added > 0; +} + +static Object *cons_object(ObjFile *obj) +{ + Object *robj; + Vector3 *varr, *narr; + Vector2 *tarr; + + int nelem = obj->f.size() * 3; + + try { + robj = new Object; + varr = new Vector3[nelem]; + narr = new Vector3[nelem]; + tarr = new Vector2[nelem]; + } + catch(...) { + return 0; + } + /*if(obj->cur_obj.length() > 0) { + robj->set_name(obj->cur_obj.c_str()); + }*/ + + // 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(Vector2(0, 0)); + added_tc = true; + } + + for(size_t i=0; if.size(); i++) { + for(int j=0; j<3; j++) { + int idx = i * 3 + j; + ObjFace *f = &obj->f[i]; + + varr[idx] = obj->v[f->v[j]]; + narr[idx] = obj->vn[f->n[j] < 0 ? 0 : f->n[j]]; + + float t = obj->vt[f->t[j] < 0 ? 0 : f->t[j]].x; + float s = obj->vt[f->t[j] < 0 ? 0 : f->t[j]].y; + tarr[idx] = Vector2(t, s); + } + } + + if(added_norm) { + obj->vn.pop_back(); + } + if(added_tc) { + obj->vt.pop_back(); + } + + Mesh *mesh = robj->get_mesh(); + mesh->set_attrib(MESH_ATTR_VERTEX, nelem, 3, &varr->x); + mesh->set_attrib(MESH_ATTR_NORMAL, nelem, 3, &narr->x); + mesh->set_attrib(MESH_ATTR_TEXCOORD, nelem, 2, &tarr->x); + + delete [] varr; + delete [] narr; + delete [] tarr; + return robj; +} + +static bool read_materials(FILE *fp, vector *vmtl) +{ + ObjMat 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) { + 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_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: + { + Color 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) { + 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 { + (*vec)[i] = atof(tok); + } + } + return true; +} + +static bool parse_color(Color *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; + } + (*col)[i] = atof(tok); + } + return true; +} + +static bool parse_face(ObjFace *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 : ""; +} diff -r 48dce4ee4850 -r f9274bebe55e src/scene.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scene.cc Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,67 @@ +#include +#include +#include "scene.h" + +Scene::~Scene() +{ + for(size_t i=0; irender(); + } +} diff -r 48dce4ee4850 -r f9274bebe55e src/scene.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/scene.h Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,34 @@ +#ifndef SCENE_H_ +#define SCENE_H_ + +#include +#include +#include "mesh.h" +#include "object.h" + +class Scene { +private: + std::vector objects; + std::vector meshes; + + bool load_obj(FILE *fp); // defined in objfile.cc + +public: + ~Scene(); + + bool load(const char *fname); + + void add_object(Object *obj); + void add_mesh(Mesh *mesh); + + int get_num_objects() const; + int get_num_meshes() const; + + Object *get_object(int idx) const; + Mesh *get_mesh(int idx) const; + + void update(long msec); + void render() const; +}; + +#endif // SCENE_H_ diff -r 48dce4ee4850 -r f9274bebe55e src/vmath.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vmath.h Thu Jul 17 02:35:19 2014 +0300 @@ -0,0 +1,37 @@ +#ifndef VMATH_H_ +#define VMATH_H_ + +class Vector2 { +public: + float x, y; + + Vector2() : x(0), y(0) {} + Vector2(float xa, float ya) : x(xa), y(ya) {} + + float &operator [](int idx) { return (&x)[idx]; } + const float &operator [](int idx) const { return (&x)[idx]; } +}; + +class Vector3 { +public: + float x, y, z; + + Vector3() : x(0), y(0), z(0) {} + Vector3(float xa, float ya, float za) : x(xa), y(ya), z(za) {} + + float &operator [](int idx) { return (&x)[idx]; } + const float &operator [](int idx) const { return (&x)[idx]; } +}; + +class Vector4 { +public: + float x, y, z, w; + + Vector4() : x(0), y(0), z(0), w(0) {} + Vector4(float xa, float ya, float za, float wa) : x(xa), y(ya), z(za), w(wa) {} + + float &operator [](int idx) { return (&x)[idx]; } + const float &operator [](int idx) const { return (&x)[idx]; } +}; + +#endif // VMATH_H_