UPDATED 2010-03-02 11:07: There was a minor bug in the code which caused to tokens recognition to file. You won’t encounter it in an obj file, but I fixed it for the good order.
I can remember the first time I wrote my Obj Mesh loader. It took hours. Today I needed also an obj mesh loader and this time it took mere minutes (under 15 minutes at least), so I have decided to share it. Keep in mind you should most likely separate it in header and source files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /** * The MIT License * * Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <string> #include <vector> #include <sstream> #include <fstream> #define TOKEN_VERTEX_POS "v" #define TOKEN_VERTEX_NOR "vn" #define TOKEN_VERTEX_TEX "vt" #define TOKEN_FACE "f" struct Vector2f{ float x, y; }; struct Vector3f{ float x, y, z; }; struct ObjMeshVertex{ Vector3f pos; Vector2f texcoord; Vector3f normal; }; /* This is a triangle, that we can render */ struct ObjMeshFace{ ObjMeshVertex vertices[3]; }; /* This contains a list of triangles */ struct ObjMesh{ std::vector<ObjMeshFace> faces; }; /* Internal structure */ struct _ObjMeshFaceIndex{ int pos_index[3]; int tex_index[3]; int nor_index[3]; }; /* Call this function to load a model, only loads trianglized meshes */ ObjMesh LoadObjMesh(std::string filename){ ObjMesh myMesh; std::vector<Vector3f> positions; std::vector<Vector2f> texcoords; std::vector<Vector3f> normals; std::vector<_ObjMeshFaceIndex> faces; /** * Load file, parse it * Lines beginning with: * '#' are comments can be ignored * 'v' are vertices positions (3 floats that can be positive or negative) * 'vt' are vertices texcoords (2 floats that can be positive or negative) * 'vn' are vertices normals (3 floats that can be positive or negative) * 'f' are faces, 3 values that contain 3 values which are separated by / and <space> */ char char_buffer[256]; std::ifstream filestream; filestream.open(filename.c_str()); while(filestream.eof() == false &amp;amp;&amp;amp; filestream.bad() == false){ memset(char_buffer, 0, 256); filestream.getline(char_buffer, 256); /* FIXED: * Where strlen stood was first 256, however this would cause a problem * when you only have a token */ std::stringstream str_stream(std::string(char_buffer, strlen(char_buffer))); std::string type_str; str_stream >> type_str; if(type_str == TOKEN_VERTEX_POS){ Vector3f pos; str_stream >> pos.x >> pos.y >> pos.z; positions.push_back(pos); }else if(type_str == TOKEN_VERTEX_TEX){ Vector2f tex; str_stream >> tex.x >> tex.y; texcoords.push_back(tex); }else if(type_str == TOKEN_VERTEX_NOR){ Vector3f nor; str_stream >> nor.x >> nor.y >> nor.z; normals.push_back(nor); }else if(type_str == TOKEN_FACE){ _ObjMeshFaceIndex face_index; char interupt; for(int i = 0; i < 3; ++i){ str_stream >> face_index.pos_index[i] >> interupt >> face_index.tex_index[i] >> interupt >> face_index.nor_index[i]; } faces.push_back(face_index); } } filestream.close(); for(size_t i = 0; i < faces.size(); ++i){ ObjMeshFace face; for(size_t j = 0; j < 3; ++j){ face.vertices[j].pos = positions[faces[i].pos_index[j] - 1]; face.vertices[j].texcoord = texcoords[faces[i].tex_index[j] - 1]; face.vertices[j].normal = normals[faces[i].nor_index[j] - 1]; } myMesh.faces.push_back(face); } return myMesh; } |