JeffSventora Posted April 30, 2013 Author Share Posted April 30, 2013 Wavefront OBJ (.obj) is a popular format for exporting 3D static meshes in Maya and 3DS Max. What makes it popular is the unbelievable ease in which loading meshes can be attained. Please remember, this is for STATIC meshes, no animation data. I also did not release code to read in materials but that can be done easily with some research.By default, Waveffront OBJ files are organized in a way that is pretty friendly with OpenGL but we are going to take the imported data and convert it to an indexed mesh. An indexed mesh is one that does not retain redundant data and uses indices to reference correct vertices when drawing primitives to the screen.If you want to know more about Wavefront OBJ files, you can look here:[http://www.fileforma…ontobj/egff.htm](http://www.fileformat.info/format/wavefrontobj/egff.htm)Here is the code. You can see that I organized the code in an easy to read way, you have a function that loads the mesh, easy enough![http://pastebin.com/Qk9RecHE](http://pastebin.com/Qk9RecHE)```#include #include #include #include #include using std::vector;using std::stringstream;using std::string;using std::ifstream;using std::ofstream;#define TAG_VERTEX_POS "v"#define TAG_VERTEX_NORM "vn"#define TAG_VERTEX_TEX "vt"#define TAG_FACE "f"typedef struct { float x, y, z; } Vec3F;typedef struct { float x, y; } Vec2F;struct obj_vert{Vec3F position;Vec3F normal;Vec2F tex_coord;bool operator==(const obj_vert& comp) const{if( !(comp.position.x == position.x) ||!(comp.position.y == position.y) ||!(comp.position.z == position.z) )return false;if( !(comp.normal.x == normal.x) ||!(comp.normal.y == normal.y) ||!(comp.normal.z == normal.z) )return false;if( !(comp.tex_coord.x == tex_coord.x) ||!(comp.tex_coord.y == tex_coord.y) )return false;return true;}};struct obj_face{obj_vert vertices[3];};struct obj_face_index{int pos_indices[3];int norm_indices[3];int tex_indices[3];};typedef struct _mesh{obj_vert* verts;int* indices;int num_verts;int num_indices;_mesh(void){verts = nullptr;indices = nullptr;}~_mesh(void){if(verts != nullptr){delete [] verts;verts = nullptr;}if(indices != nullptr){delete [] indices;indices = nullptr;}}} mesh, *lpmesh;// Helper Functionslpmesh load_mesh(const char* file);int contains_vector(const vector& vec, obj_vert check);bool is_obj_file(const char* filename);bool write_mesh(const lpmesh write_mesh, const char* filename);// Entry Pointint main(int argc, char* argv[]){for(int i = 1; i < argc; ++i){if(is_obj_file(argv[i])){lpmesh in_mesh = load_mesh(argv[i]);if(!write_mesh(in_mesh, argv[i]))printf("FAILED\n\n");elseprintf("SUCCESS\n\n");}}return getchar();}// helper Function Definitionslpmesh load_mesh(const char* file){// Used to build the unique list and indicesvector positions;vector normals;vector tex_coords;vector faces;vector unique_verts;vector indices;ifstream filestream;filestream.open(file);if(!filestream.is_open())return nullptr;// Read every line of the .obj filestring line_stream;while(std::getline(filestream, line_stream)){stringstream str_stream(line_stream);string type_str;str_stream >> type_str;if(type_str == TAG_VERTEX_POS){Vec3F pos;str_stream >> pos.x >> pos.y >> pos.z;positions.push_back(pos);}else if(type_str == TAG_VERTEX_TEX){Vec2F tex;str_stream >> tex.x >> tex.y;tex_coords.push_back(tex);}else if(type_str == TAG_VERTEX_NORM){Vec3F norm;str_stream >> norm.x >> norm.y >> norm.z;normals.push_back(norm);}else if(type_str == TAG_FACE){obj_face_index face_index;char interrupt;for(int i = 0; i < 3; ++i){str_stream >> face_index.pos_indices[i] >> interrupt>> face_index.tex_indices[i] >> interrupt>> face_index.norm_indices[i];}faces.push_back(face_index);}}// Close the filefilestream.close();// Build unique vertex listfor(size_t i = 0; i < faces.size(); ++i){for(int j = 0; j < 3; ++j){obj_vert new_vert;new_vert.position = positions[faces[i].pos_indices[j] - 1];new_vert.normal = normals[faces[i].norm_indices[j] - 1];new_vert.tex_coord = tex_coords[faces[i].tex_indices[j] - 1];int uindex = contains_vector(unique_verts, new_vert);if(uindex >= 0)indices.push_back(uindex);else{indices.push_back((int)unique_verts.size());unique_verts.push_back(new_vert);}}}// Fill out the meshlpmesh new_mesh = new mesh();new_mesh->num_verts = unique_verts.size();new_mesh->verts = new obj_vert[new_mesh->num_verts];new_mesh->num_indices = indices.size();new_mesh->indices = new int[new_mesh->num_indices];int size_of_vert = sizeof(obj_vert);memcpy(new_mesh->verts, &unique_verts[0], size_of_vert * new_mesh->num_verts);memcpy(new_mesh->indices, &indices[0], sizeof(int) * new_mesh->num_indices);return new_mesh;}int contains_vector(const vector& vec, obj_vert check){for(size_t i = 0; i < vec.size(); ++i)if(vec[i] == check)return (int)i;return -1;}bool is_obj_file(const char* filename){unsigned extension_index = strlen(filename) - 4;string file_mod = filename + extension_index;if(file_mod != ".obj")return false;return true;}bool write_mesh(const lpmesh write_mesh, const char* filename){printf("Converting \"%s\"\n", filename);if(write_mesh == nullptr)return false;string file_mod = filename;unsigned filename_len = strlen(filename);unsigned ext_begin = file_mod.find('.') + 1;unsigned cur_ext_len = strlen(filename + ext_begin);char* new_file = new char[(filename_len - cur_ext_len) + 4];memcpy(new_file, filename, filename_len - cur_ext_len);sprintf(new_file + ext_begin, "smo\0");printf("Writing to \"%s\"\n", new_file);ofstream file;file.open(new_file, std::ios_base::out | std::ios_base::binary);if(!file.is_open())return false;// Write out the meshfile.write((char*)&write_mesh->num_verts, sizeof(int));file.write((char*)&write_mesh->num_indices, sizeof(int));file.write((char*)&write_mesh->verts[0], sizeof(obj_vert) * write_mesh->num_verts);file.write((char*)&write_mesh->indices[0], sizeof(int) * write_mesh->num_indices);// Close the filefile.close();if(new_file != nullptr){delete [] new_file;new_file = nullptr;}return true;}[/i][/i][/i][/i][/i][/i][/i]``` Link to comment Share on other sites More sharing options...
blkcrow Posted April 30, 2013 Share Posted April 30, 2013 even though i dont see me using it anytime soon ![:P](http://www.touchofdeathforums.com/community/public/style_emoticons/<#EMO_DIR#>/tongue.png) its nice to have it thanks for the release Link to comment Share on other sites More sharing options...
Mal Posted April 30, 2013 Share Posted April 30, 2013 You may want to re-format your code snippet for readability purposes. Link to comment Share on other sites More sharing options...
JeffSventora Posted April 30, 2013 Author Share Posted April 30, 2013 I tried, stupid thing keeps messing it up. Link to comment Share on other sites More sharing options...
Mal Posted April 30, 2013 Share Posted April 30, 2013 > I tried, stupid thing keeps messing it up.It shouldn't. What you'll have to do is go into edit mode, clear the quote entirely, type in the code blocks, then paste the text straight from the IDE into the quotes. Any time you edit the topic it's going to screw the formatting up, which is stupid in and of itself. The other alternative is to pastebin it. Link to comment Share on other sites More sharing options...
JeffSventora Posted May 1, 2013 Author Share Posted May 1, 2013 I organized it and I made a pastebin link available. Link to comment Share on other sites More sharing options...
Mal Posted May 1, 2013 Share Posted May 1, 2013 > I organized it and I made a pastebin link available.Awesome. Way more readable now. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now