diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index b014c05..68bb055 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -229,8 +229,6 @@ typedef struct { } mesh_t; typedef struct { - int smoothingGroupId; // Smoothing group id. - int _pad0; std::string name; mesh_t mesh; } shape_t; @@ -375,14 +373,26 @@ namespace tinyobj { MaterialReader::~MaterialReader() {} -struct vertex_index { +struct vertex_index_t { int v_idx, vt_idx, vn_idx; - vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} - explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} - vertex_index(int vidx, int vtidx, int vnidx) + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} }; +// Internal data structure for face representation +// index + smoothing group. +struct face_t { + int smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. + int pad_; + std::vector vertex_indices; // face vertex indices. + + face_t() : smoothing_group_id(0) { + } +}; + + struct tag_sizes { tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} int num_ints; @@ -754,12 +764,12 @@ static tag_sizes parseTagTriple(const char **token) { // Parse triples with index offsets: i, i/j/k, i//k, i/j static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, - vertex_index *ret) { + vertex_index_t *ret) { if (!ret) { return false; } - vertex_index vi(-1); + vertex_index_t vi(-1); if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { return false; @@ -807,8 +817,8 @@ static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, } // Parse raw triples: i, i/j/k, i//k, i/j -static vertex_index parseRawTriple(const char **token) { - vertex_index vi(static_cast(0)); // 0 is an invalid index in OBJ +static vertex_index_t parseRawTriple(const char **token) { + vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ vi.v_idx = atoi((*token)); (*token) += strcspn((*token), "/ \t\r"); @@ -992,8 +1002,9 @@ static int pnpoly(int nvert, float *vertx, float *verty, float testx, float test return c; } +// TODO(syoyo): refactor function. static bool exportFaceGroupToShape( - shape_t *shape, const std::vector > &faceGroup, + shape_t *shape, const std::vector &faceGroup, const std::vector &tags, const int material_id, const std::string &name, bool triangulate, const std::vector &v) { if (faceGroup.empty()) { @@ -1002,21 +1013,21 @@ static bool exportFaceGroupToShape( // Flatten vertices and indices for (size_t i = 0; i < faceGroup.size(); i++) { - const std::vector &face = faceGroup[i]; + const face_t &face = faceGroup[i]; - vertex_index i0 = face[0]; - vertex_index i1(-1); - vertex_index i2 = face[1]; + vertex_index_t i0 = face.vertex_indices[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face.vertex_indices[1]; - size_t npolys = face.size(); + size_t npolys = face.vertex_indices.size(); if (triangulate) { // find the two axes to work in size_t axes[2] = { 1, 2 }; for(size_t k = 0; k < npolys; ++k) { - i0 = face[(k+0)%npolys]; - i1 = face[(k+1)%npolys]; - i2 = face[(k+2)%npolys]; + i0 = face.vertex_indices[(k+0)%npolys]; + i1 = face.vertex_indices[(k+1)%npolys]; + i2 = face.vertex_indices[(k+2)%npolys]; size_t vi0 = size_t(i0.v_idx); size_t vi1 = size_t(i1.v_idx); size_t vi2 = size_t(i2.v_idx); @@ -1053,8 +1064,8 @@ static bool exportFaceGroupToShape( real_t area = 0; for(size_t k = 0; k < npolys; ++k) { - i0 = face[(k+0)%npolys]; - i1 = face[(k+1)%npolys]; + i0 = face.vertex_indices[(k+0)%npolys]; + i1 = face.vertex_indices[(k+1)%npolys]; size_t vi0 = size_t(i0.v_idx); size_t vi1 = size_t(i1.v_idx); real_t v0x = v[vi0*3+axes[0]]; @@ -1066,19 +1077,19 @@ static bool exportFaceGroupToShape( int maxRounds = 10; // arbitrary max loop count to protect against unexpected errors - std::vector remainingFace = face; + face_t remainingFace = face; // copy size_t guess_vert = 0; - vertex_index ind[3]; + vertex_index_t ind[3]; real_t vx[3]; real_t vy[3]; - while( remainingFace.size() > 3 && maxRounds > 0 ) { - npolys = remainingFace.size(); + while( remainingFace.vertex_indices.size() > 3 && maxRounds > 0 ) { + npolys = remainingFace.vertex_indices.size(); if( guess_vert >= npolys ) { maxRounds -= 1; guess_vert -= npolys; } for( size_t k = 0; k < 3; k++ ) { - ind[k] = remainingFace[(guess_vert+k)%npolys]; + ind[k] = remainingFace.vertex_indices[(guess_vert+k)%npolys]; size_t vi = size_t(ind[k].v_idx); vx[k] = v[vi*3+axes[0]]; vy[k] = v[vi*3+axes[1]]; @@ -1094,7 +1105,7 @@ static bool exportFaceGroupToShape( // check all other verts in case they are inside this triangle bool overlap = false; for( size_t otherVert = 3; otherVert < npolys; ++otherVert ) { - size_t ovi = size_t(remainingFace[(guess_vert+otherVert)%npolys].v_idx); + size_t ovi = size_t(remainingFace.vertex_indices[(guess_vert+otherVert)%npolys].v_idx); real_t tx = v[ovi*3+axes[0]]; real_t ty = v[ovi*3+axes[1]]; if( pnpoly( 3, vx, vy, tx, ty ) ) { @@ -1129,16 +1140,16 @@ static bool exportFaceGroupToShape( // remove v1 from the list size_t removed_vert_index = (guess_vert+1)%npolys; while( removed_vert_index + 1 < npolys ) { - remainingFace[removed_vert_index] = remainingFace[removed_vert_index+1]; + remainingFace.vertex_indices[removed_vert_index] = remainingFace.vertex_indices[removed_vert_index+1]; removed_vert_index += 1; } - remainingFace.pop_back(); + remainingFace.vertex_indices.pop_back(); } - if( remainingFace.size() == 3 ) { - i0 = remainingFace[0]; - i1 = remainingFace[1]; - i2 = remainingFace[2]; + if( remainingFace.vertex_indices.size() == 3 ) { + i0 = remainingFace.vertex_indices[0]; + i1 = remainingFace.vertex_indices[1]; + i2 = remainingFace.vertex_indices[2]; { index_t idx0, idx1, idx2; idx0.vertex_index = i0.v_idx; @@ -1162,9 +1173,9 @@ static bool exportFaceGroupToShape( } else { for (size_t k = 0; k < npolys; k++) { index_t idx; - idx.vertex_index = face[k].v_idx; - idx.normal_index = face[k].vn_idx; - idx.texcoord_index = face[k].vt_idx; + idx.vertex_index = face.vertex_indices[k].v_idx; + idx.normal_index = face.vertex_indices[k].vn_idx; + idx.texcoord_index = face.vertex_indices[k].vt_idx; shape->mesh.indices.push_back(idx); } @@ -1679,7 +1690,8 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, std::vector vt; std::vector vc; std::vector tags; - std::vector > faceGroup; + std::vector smoothing_groups; + std::vector faceGroup; std::string name; // material @@ -1687,10 +1699,9 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, int material = -1; // smoothing group id - int currentSmoothingId = 0; // Initial value. 0 means no smoothing. + int current_smoothing_id = 0; // Initial value. 0 means no smoothing. shape_t shape; - shape.smoothingGroupId = currentSmoothingId; std::string linebuf; while (inStream->peek() != -1) { @@ -1762,11 +1773,13 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, token += 2; token += strspn(token, " \t"); - std::vector face; - face.reserve(3); + face_t face; + + face.smoothing_group_id = current_smoothing_id; + face.vertex_indices.reserve(3); while (!IS_NEW_LINE(token[0])) { - vertex_index vi; + vertex_index_t vi; if (!parseTriple(&token, static_cast(v.size() / 3), static_cast(vn.size() / 3), static_cast(vt.size() / 2), &vi)) { @@ -1776,14 +1789,13 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, return false; } - face.push_back(vi); + face.vertex_indices.push_back(vi); size_t n = strspn(token, " \t\r"); token += n; } // replace with emplace_back + std::move on C++11 - faceGroup.push_back(std::vector()); - faceGroup[faceGroup.size() - 1].swap(face); + faceGroup.push_back(face); continue; } @@ -1870,7 +1882,6 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, } shape = shape_t(); - shape.smoothingGroupId = currentSmoothingId; // material = -1; faceGroup.clear(); @@ -1908,7 +1919,6 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, // material = -1; faceGroup.clear(); shape = shape_t(); - shape.smoothingGroupId = currentSmoothingId; // @todo { multiple object name? } token += 2; @@ -1952,28 +1962,32 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, if (token[0] == 's' && IS_SPACE(token[1])) { // smoothing group id token += 2; - int smGroupId = parseInt(&token); - if (smGroupId == currentSmoothingId) - continue; // No change in smoothing group. + // skip space. + token += strspn(token, " \t"); // skip space - // Encountering new smoothing group Id. - // Export the current face group - if (!faceGroup.empty()) { - bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, - triangulate, v); - if (ret) { - shapes->push_back(shape); - } - } + if (token[0] == '\0') { + continue; + } - // Clear the face group and initialize the shape with new smoothing group id - // and keep the existing name and materials of the shape. - faceGroup.clear(); - shape.mesh.indices.clear(); - shape.mesh.num_face_vertices.clear(); - shape.smoothingGroupId = smGroupId; - currentSmoothingId = smGroupId; + if (token[0] == '\r' || token[1] == '\n') { + continue; + } + + if (strlen(token) >= 3) { + if (token[0] == 'o' && token[1] == 'f' && token[2] == 'f') { + current_smoothing_id = 0; + } + } else { + // assume number + int smGroupId = parseInt(&token); + if (smGroupId < 0) { + // ??? + continue; + } + + current_smoothing_id = smGroupId; + } continue; } // smoothing group id @@ -2090,7 +2104,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, indices.clear(); while (!IS_NEW_LINE(token[0])) { - vertex_index vi = parseRawTriple(&token); + vertex_index_t vi = parseRawTriple(&token); index_t idx; idx.vertex_index = vi.v_idx;