aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyoyo Fujita <syoyo@lighttransport.com>2021-03-08 15:32:47 +0900
committerGitHub <noreply@github.com>2021-03-08 15:32:47 +0900
commit7ba4b652ee0c5175ec8abf66199e84d88adf11f1 (patch)
tree39f6b41d1d58d5efa284d6f3228cadbbb181d851
parent9173980d1de273b17eba5e10eb189e8b4be89425 (diff)
downloadtinyobjloader-7ba4b652ee0c5175ec8abf66199e84d88adf11f1.tar.gz
Use simple triangulation rule for the quad face when triangulation. This partially solves issue no. 295. (#296)
-rw-r--r--models/issue-295-trianguation-failure.obj38
-rw-r--r--tests/tester.cc34
-rw-r--r--tiny_obj_loader.h475
3 files changed, 368 insertions, 179 deletions
diff --git a/models/issue-295-trianguation-failure.obj b/models/issue-295-trianguation-failure.obj
new file mode 100644
index 0000000..f3b2649
--- /dev/null
+++ b/models/issue-295-trianguation-failure.obj
@@ -0,0 +1,38 @@
+#mtllib invalid.mtl
+v 14678.0 0.0 9605.0
+v 14678.0 1.0 9605.0
+v 14678.0 0.0 9606.0
+v 14678.0 1.0 9606.0
+v 14678.0 0.0 9607.0
+v 14678.0 1.0 9607.0
+v 14678.0 0.0 9608.0
+v 14678.0 1.0 9608.0
+v 14679.0 0.0 9605.0
+v 14679.0 1.0 9605.0
+v 14679.0 0.0 9606.0
+v 14679.0 1.0 9606.0
+v 14679.0 0.0 9607.0
+v 14679.0 1.0 9607.0
+v 14679.0 0.0 9608.0
+v 14679.0 1.0 9608.0
+# UV
+vt 0.0 0.0
+vt 1.0 0.0
+vt 1.0 1.0
+vt 0.0 1.0
+#usemtl invalid
+o invalid
+f 9/4 11/1 3/2 1/3
+f 4/1 12/2 10/3 2/4
+f 2/3 10/4 9/1 1/2
+f 3/2 4/3 2/4 1/1
+f 10/3 12/4 11/1 9/2
+f 11/4 13/1 5/2 3/3
+f 6/1 14/2 12/3 4/4
+f 5/2 6/3 4/4 3/1
+f 12/3 14/4 13/1 11/2
+f 13/4 15/1 7/2 5/3
+f 8/1 16/2 14/3 6/4
+f 15/2 16/3 8/4 7/1
+f 7/2 8/3 6/4 5/1
+f 14/3 16/4 15/1 13/2
diff --git a/tests/tester.cc b/tests/tester.cc
index 0fd0dbc..ebb5290 100644
--- a/tests/tester.cc
+++ b/tests/tester.cc
@@ -1332,6 +1332,38 @@ void test_mtl_filename_with_whitespace_issue46() {
TEST_CHECK("green" == materials[0].name);
}
+void test_face_missing_issue295() {
+ tinyobj::attrib_t attrib;
+ std::vector<tinyobj::shape_t> shapes;
+ std::vector<tinyobj::material_t> materials;
+
+ std::string warn;
+ std::string err;
+ bool ret = tinyobj::LoadObj(
+ &attrib, &shapes, &materials, &warn, &err,
+ "../models/issue-295-trianguation-failure.obj",
+ gMtlBasePath, /* triangualte */true);
+
+ TEST_CHECK(warn.empty());
+
+ if (!warn.empty()) {
+ std::cout << "WARN: " << warn << std::endl;
+ }
+
+ if (!err.empty()) {
+ std::cerr << "ERR: " << err << std::endl;
+ }
+
+ TEST_CHECK(true == ret);
+ TEST_CHECK(1 == shapes.size());
+
+ // 14 quad faces are triangulated into 28 triangles.
+ TEST_CHECK(28 == shapes[0].mesh.num_face_vertices.size());
+ TEST_CHECK(28 == shapes[0].mesh.smoothing_group_ids.size());
+ TEST_CHECK(28 == shapes[0].mesh.material_ids.size());
+ TEST_CHECK((3 * 28) == shapes[0].mesh.indices.size()); // 28 triangle faces x 3
+}
+
// Fuzzer test.
// Just check if it does not crash.
// Disable by default since Windows filesystem can't create filename of afl
@@ -1433,4 +1465,6 @@ TEST_LIST = {
test_texres_texopt_issue248},
{"test_mtl_filename_with_whitespace_issue46",
test_mtl_filename_with_whitespace_issue46},
+ {"test_face_missing_issue295",
+ test_face_missing_issue295},
{NULL, NULL}};
diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h
index 99213f6..4bfd7b7 100644
--- a/tiny_obj_loader.h
+++ b/tiny_obj_loader.h
@@ -1,7 +1,7 @@
/*
The MIT License (MIT)
-Copyright (c) 2012-2018 Syoyo Fujita and many contributors.
+Copyright (c) 2012-Present, Syoyo Fujita and many contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -1366,8 +1366,8 @@ static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) {
static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
const std::vector<tag_t> &tags,
const int material_id, const std::string &name,
- bool triangulate,
- const std::vector<real_t> &v) {
+ bool triangulate, const std::vector<real_t> &v,
+ std::string *warn) {
if (prim_group.IsEmpty()) {
return false;
}
@@ -1384,30 +1384,34 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
if (npolys < 3) {
// Face must have 3+ vertices.
+ if (warn) {
+ (*warn) += "Degenerated face found\n.";
+ }
continue;
}
- vertex_index_t i0 = face.vertex_indices[0];
- vertex_index_t i1(-1);
- vertex_index_t i2 = face.vertex_indices[1];
-
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.vertex_indices[(k + 0) % npolys];
- i1 = face.vertex_indices[(k + 1) % npolys];
- i2 = face.vertex_indices[(k + 2) % npolys];
+ if (npolys == 4) {
+ vertex_index_t i0 = face.vertex_indices[0];
+ vertex_index_t i1 = face.vertex_indices[1];
+ vertex_index_t i2 = face.vertex_indices[2];
+ vertex_index_t i3 = face.vertex_indices[3];
+
size_t vi0 = size_t(i0.v_idx);
size_t vi1 = size_t(i1.v_idx);
size_t vi2 = size_t(i2.v_idx);
+ size_t vi3 = size_t(i3.v_idx);
if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
- ((3 * vi2 + 2) >= v.size())) {
+ ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) {
// Invalid triangle.
// FIXME(syoyo): Is it ok to simply skip this invalid triangle?
+ if (warn) {
+ (*warn) += "Face with invalid vertex index found.\n";
+ }
continue;
}
+
real_t v0x = v[vi0 * 3 + 0];
real_t v0y = v[vi0 * 3 + 1];
real_t v0z = v[vi0 * 3 + 2];
@@ -1417,186 +1421,297 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
real_t v2x = v[vi2 * 3 + 0];
real_t v2y = v[vi2 * 3 + 1];
real_t v2z = v[vi2 * 3 + 2];
- real_t e0x = v1x - v0x;
- real_t e0y = v1y - v0y;
- real_t e0z = v1z - v0z;
- real_t e1x = v2x - v1x;
- real_t e1y = v2y - v1y;
- real_t e1z = v2z - v1z;
- real_t cx = std::fabs(e0y * e1z - e0z * e1y);
- real_t cy = std::fabs(e0z * e1x - e0x * e1z);
- real_t cz = std::fabs(e0x * e1y - e0y * e1x);
- const real_t epsilon = std::numeric_limits<real_t>::epsilon();
- if (cx > epsilon || cy > epsilon || cz > epsilon) {
- // found a corner
- if (cx > cy && cx > cz) {
- } else {
- axes[0] = 0;
- if (cz > cx && cz > cy) axes[1] = 1;
- }
- break;
- }
- }
-
- real_t area = 0;
- for (size_t k = 0; k < npolys; ++k) {
- 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);
- if (((vi0 * 3 + axes[0]) >= v.size()) ||
- ((vi0 * 3 + axes[1]) >= v.size()) ||
- ((vi1 * 3 + axes[0]) >= v.size()) ||
- ((vi1 * 3 + axes[1]) >= v.size())) {
- // Invalid index.
- continue;
- }
- real_t v0x = v[vi0 * 3 + axes[0]];
- real_t v0y = v[vi0 * 3 + axes[1]];
- real_t v1x = v[vi1 * 3 + axes[0]];
- real_t v1y = v[vi1 * 3 + axes[1]];
- area += (v0x * v1y - v0y * v1x) * static_cast<real_t>(0.5);
- }
-
- face_t remainingFace = face; // copy
- size_t guess_vert = 0;
- vertex_index_t ind[3];
- real_t vx[3];
- real_t vy[3];
-
- // How many iterations can we do without decreasing the remaining
- // vertices.
- size_t remainingIterations = face.vertex_indices.size();
- size_t previousRemainingVertices = remainingFace.vertex_indices.size();
-
- while (remainingFace.vertex_indices.size() > 3 &&
- remainingIterations > 0) {
- npolys = remainingFace.vertex_indices.size();
- if (guess_vert >= npolys) {
- guess_vert -= npolys;
- }
+ real_t v3x = v[vi3 * 3 + 0];
+ real_t v3y = v[vi3 * 3 + 1];
+ real_t v3z = v[vi3 * 3 + 2];
+
+ // There are two candidates to split the quad into two triangles.
+ //
+ // Choose the shortest edge.
+ // TODO: Is it better to determine the edge to split by calculating
+ // the area of each triangle?
+ //
+ // +---+
+ // |\ |
+ // | \ |
+ // | \|
+ // +---+
+ //
+ // +---+
+ // | /|
+ // | / |
+ // |/ |
+ // +---+
+
+ real_t e02x = v2x - v0x;
+ real_t e02y = v2y - v0y;
+ real_t e02z = v2z - v0z;
+ real_t e13x = v3x - v1x;
+ real_t e13y = v3y - v1y;
+ real_t e13z = v3z - v1z;
+
+ real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z;
+ real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z;
+
+ index_t idx0, idx1, idx2, idx3;
+
+ idx0.vertex_index = i0.v_idx;
+ idx0.normal_index = i0.vn_idx;
+ idx0.texcoord_index = i0.vt_idx;
+ idx1.vertex_index = i1.v_idx;
+ idx1.normal_index = i1.vn_idx;
+ idx1.texcoord_index = i1.vt_idx;
+ idx2.vertex_index = i2.v_idx;
+ idx2.normal_index = i2.vn_idx;
+ idx2.texcoord_index = i2.vt_idx;
+ idx3.vertex_index = i3.v_idx;
+ idx3.normal_index = i3.vn_idx;
+ idx3.texcoord_index = i3.vt_idx;
+
+ if (sqr02 < sqr13) {
+ // [0, 1, 2], [0, 2, 3]
+ shape->mesh.indices.push_back(idx0);
+ shape->mesh.indices.push_back(idx1);
+ shape->mesh.indices.push_back(idx2);
- if (previousRemainingVertices != npolys) {
- // The number of remaining vertices decreased. Reset counters.
- previousRemainingVertices = npolys;
- remainingIterations = npolys;
+ shape->mesh.indices.push_back(idx0);
+ shape->mesh.indices.push_back(idx2);
+ shape->mesh.indices.push_back(idx3);
} else {
- // We didn't consume a vertex on previous iteration, reduce the
- // available iterations.
- remainingIterations--;
- }
+ // [0, 1, 3], [1, 2, 3]
+ shape->mesh.indices.push_back(idx0);
+ shape->mesh.indices.push_back(idx1);
+ shape->mesh.indices.push_back(idx3);
- for (size_t k = 0; k < 3; k++) {
- ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
- size_t vi = size_t(ind[k].v_idx);
- if (((vi * 3 + axes[0]) >= v.size()) ||
- ((vi * 3 + axes[1]) >= v.size())) {
- // ???
- vx[k] = static_cast<real_t>(0.0);
- vy[k] = static_cast<real_t>(0.0);
- } else {
- vx[k] = v[vi * 3 + axes[0]];
- vy[k] = v[vi * 3 + axes[1]];
- }
- }
- real_t e0x = vx[1] - vx[0];
- real_t e0y = vy[1] - vy[0];
- real_t e1x = vx[2] - vx[1];
- real_t e1y = vy[2] - vy[1];
- real_t cross = e0x * e1y - e0y * e1x;
- // if an internal angle
- if (cross * area < static_cast<real_t>(0.0)) {
- guess_vert += 1;
- continue;
+ shape->mesh.indices.push_back(idx1);
+ shape->mesh.indices.push_back(idx2);
+ shape->mesh.indices.push_back(idx3);
}
- // check all other verts in case they are inside this triangle
- bool overlap = false;
- for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
- size_t idx = (guess_vert + otherVert) % npolys;
+ // Two triangle faces
+ shape->mesh.num_face_vertices.push_back(3);
+ shape->mesh.num_face_vertices.push_back(3);
- if (idx >= remainingFace.vertex_indices.size()) {
- // ???
- continue;
- }
+ shape->mesh.material_ids.push_back(material_id);
+ shape->mesh.material_ids.push_back(material_id);
- size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
+ shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
+ shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
- if (((ovi * 3 + axes[0]) >= v.size()) ||
- ((ovi * 3 + axes[1]) >= v.size())) {
- // ???
+ } else {
+ vertex_index_t i0 = face.vertex_indices[0];
+ vertex_index_t i1(-1);
+ vertex_index_t i2 = face.vertex_indices[1];
+
+ // find the two axes to work in
+ size_t axes[2] = {1, 2};
+ for (size_t k = 0; k < npolys; ++k) {
+ 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);
+
+ if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
+ ((3 * vi2 + 2) >= v.size())) {
+ // Invalid triangle.
+ // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
continue;
}
- real_t tx = v[ovi * 3 + axes[0]];
- real_t ty = v[ovi * 3 + axes[1]];
- if (pnpoly(3, vx, vy, tx, ty)) {
- overlap = true;
+ real_t v0x = v[vi0 * 3 + 0];
+ real_t v0y = v[vi0 * 3 + 1];
+ real_t v0z = v[vi0 * 3 + 2];
+ real_t v1x = v[vi1 * 3 + 0];
+ real_t v1y = v[vi1 * 3 + 1];
+ real_t v1z = v[vi1 * 3 + 2];
+ real_t v2x = v[vi2 * 3 + 0];
+ real_t v2y = v[vi2 * 3 + 1];
+ real_t v2z = v[vi2 * 3 + 2];
+ real_t e0x = v1x - v0x;
+ real_t e0y = v1y - v0y;
+ real_t e0z = v1z - v0z;
+ real_t e1x = v2x - v1x;
+ real_t e1y = v2y - v1y;
+ real_t e1z = v2z - v1z;
+ real_t cx = std::fabs(e0y * e1z - e0z * e1y);
+ real_t cy = std::fabs(e0z * e1x - e0x * e1z);
+ real_t cz = std::fabs(e0x * e1y - e0y * e1x);
+ const real_t epsilon = std::numeric_limits<real_t>::epsilon();
+ if (cx > epsilon || cy > epsilon || cz > epsilon) {
+ // found a corner
+ if (cx > cy && cx > cz) {
+ } else {
+ axes[0] = 0;
+ if (cz > cx && cz > cy) axes[1] = 1;
+ }
break;
}
}
- if (overlap) {
- guess_vert += 1;
- continue;
+ real_t area = 0;
+ for (size_t k = 0; k < npolys; ++k) {
+ 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);
+ if (((vi0 * 3 + axes[0]) >= v.size()) ||
+ ((vi0 * 3 + axes[1]) >= v.size()) ||
+ ((vi1 * 3 + axes[0]) >= v.size()) ||
+ ((vi1 * 3 + axes[1]) >= v.size())) {
+ // Invalid index.
+ continue;
+ }
+ real_t v0x = v[vi0 * 3 + axes[0]];
+ real_t v0y = v[vi0 * 3 + axes[1]];
+ real_t v1x = v[vi1 * 3 + axes[0]];
+ real_t v1y = v[vi1 * 3 + axes[1]];
+ area += (v0x * v1y - v0y * v1x) * static_cast<real_t>(0.5);
}
- // this triangle is an ear
- {
- index_t idx0, idx1, idx2;
- idx0.vertex_index = ind[0].v_idx;
- idx0.normal_index = ind[0].vn_idx;
- idx0.texcoord_index = ind[0].vt_idx;
- idx1.vertex_index = ind[1].v_idx;
- idx1.normal_index = ind[1].vn_idx;
- idx1.texcoord_index = ind[1].vt_idx;
- idx2.vertex_index = ind[2].v_idx;
- idx2.normal_index = ind[2].vn_idx;
- idx2.texcoord_index = ind[2].vt_idx;
+ face_t remainingFace = face; // copy
+ size_t guess_vert = 0;
+ vertex_index_t ind[3];
+ real_t vx[3];
+ real_t vy[3];
+
+ // How many iterations can we do without decreasing the remaining
+ // vertices.
+ size_t remainingIterations = face.vertex_indices.size();
+ size_t previousRemainingVertices =
+ remainingFace.vertex_indices.size();
+
+ while (remainingFace.vertex_indices.size() > 3 &&
+ remainingIterations > 0) {
+ npolys = remainingFace.vertex_indices.size();
+ if (guess_vert >= npolys) {
+ guess_vert -= npolys;
+ }
- shape->mesh.indices.push_back(idx0);
- shape->mesh.indices.push_back(idx1);
- shape->mesh.indices.push_back(idx2);
+ if (previousRemainingVertices != npolys) {
+ // The number of remaining vertices decreased. Reset counters.
+ previousRemainingVertices = npolys;
+ remainingIterations = npolys;
+ } else {
+ // We didn't consume a vertex on previous iteration, reduce the
+ // available iterations.
+ remainingIterations--;
+ }
- shape->mesh.num_face_vertices.push_back(3);
- shape->mesh.material_ids.push_back(material_id);
- shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
- }
+ for (size_t k = 0; k < 3; k++) {
+ ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
+ size_t vi = size_t(ind[k].v_idx);
+ if (((vi * 3 + axes[0]) >= v.size()) ||
+ ((vi * 3 + axes[1]) >= v.size())) {
+ // ???
+ vx[k] = static_cast<real_t>(0.0);
+ vy[k] = static_cast<real_t>(0.0);
+ } else {
+ vx[k] = v[vi * 3 + axes[0]];
+ vy[k] = v[vi * 3 + axes[1]];
+ }
+ }
+ real_t e0x = vx[1] - vx[0];
+ real_t e0y = vy[1] - vy[0];
+ real_t e1x = vx[2] - vx[1];
+ real_t e1y = vy[2] - vy[1];
+ real_t cross = e0x * e1y - e0y * e1x;
+ // if an internal angle
+ if (cross * area < static_cast<real_t>(0.0)) {
+ guess_vert += 1;
+ continue;
+ }
- // remove v1 from the list
- size_t removed_vert_index = (guess_vert + 1) % npolys;
- while (removed_vert_index + 1 < npolys) {
- remainingFace.vertex_indices[removed_vert_index] =
- remainingFace.vertex_indices[removed_vert_index + 1];
- removed_vert_index += 1;
- }
- remainingFace.vertex_indices.pop_back();
- }
+ // check all other verts in case they are inside this triangle
+ bool overlap = false;
+ for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
+ size_t idx = (guess_vert + otherVert) % npolys;
+
+ if (idx >= remainingFace.vertex_indices.size()) {
+ // ???
+ continue;
+ }
+
+ size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
+
+ if (((ovi * 3 + axes[0]) >= v.size()) ||
+ ((ovi * 3 + axes[1]) >= v.size())) {
+ // ???
+ continue;
+ }
+ real_t tx = v[ovi * 3 + axes[0]];
+ real_t ty = v[ovi * 3 + axes[1]];
+ if (pnpoly(3, vx, vy, tx, ty)) {
+ overlap = true;
+ break;
+ }
+ }
- 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;
- idx0.normal_index = i0.vn_idx;
- idx0.texcoord_index = i0.vt_idx;
- idx1.vertex_index = i1.v_idx;
- idx1.normal_index = i1.vn_idx;
- idx1.texcoord_index = i1.vt_idx;
- idx2.vertex_index = i2.v_idx;
- idx2.normal_index = i2.vn_idx;
- idx2.texcoord_index = i2.vt_idx;
+ if (overlap) {
+ guess_vert += 1;
+ continue;
+ }
- shape->mesh.indices.push_back(idx0);
- shape->mesh.indices.push_back(idx1);
- shape->mesh.indices.push_back(idx2);
+ // this triangle is an ear
+ {
+ index_t idx0, idx1, idx2;
+ idx0.vertex_index = ind[0].v_idx;
+ idx0.normal_index = ind[0].vn_idx;
+ idx0.texcoord_index = ind[0].vt_idx;
+ idx1.vertex_index = ind[1].v_idx;
+ idx1.normal_index = ind[1].vn_idx;
+ idx1.texcoord_index = ind[1].vt_idx;
+ idx2.vertex_index = ind[2].v_idx;
+ idx2.normal_index = ind[2].vn_idx;
+ idx2.texcoord_index = ind[2].vt_idx;
+
+ shape->mesh.indices.push_back(idx0);
+ shape->mesh.indices.push_back(idx1);
+ shape->mesh.indices.push_back(idx2);
+
+ shape->mesh.num_face_vertices.push_back(3);
+ shape->mesh.material_ids.push_back(material_id);
+ shape->mesh.smoothing_group_ids.push_back(
+ face.smoothing_group_id);
+ }
- shape->mesh.num_face_vertices.push_back(3);
- shape->mesh.material_ids.push_back(material_id);
- shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
+ // remove v1 from the list
+ size_t removed_vert_index = (guess_vert + 1) % npolys;
+ while (removed_vert_index + 1 < npolys) {
+ remainingFace.vertex_indices[removed_vert_index] =
+ remainingFace.vertex_indices[removed_vert_index + 1];
+ removed_vert_index += 1;
+ }
+ remainingFace.vertex_indices.pop_back();
}
- }
+
+ 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;
+ idx0.normal_index = i0.vn_idx;
+ idx0.texcoord_index = i0.vt_idx;
+ idx1.vertex_index = i1.v_idx;
+ idx1.normal_index = i1.vn_idx;
+ idx1.texcoord_index = i1.vt_idx;
+ idx2.vertex_index = i2.v_idx;
+ idx2.normal_index = i2.vn_idx;
+ idx2.texcoord_index = i2.vt_idx;
+
+ shape->mesh.indices.push_back(idx0);
+ shape->mesh.indices.push_back(idx1);
+ shape->mesh.indices.push_back(idx2);
+
+ shape->mesh.num_face_vertices.push_back(3);
+ shape->mesh.material_ids.push_back(material_id);
+ shape->mesh.smoothing_group_ids.push_back(
+ face.smoothing_group_id);
+ }
+ }
+ } // npolys
} else {
for (size_t k = 0; k < npolys; k++) {
index_t idx;
@@ -2174,7 +2289,7 @@ bool MaterialStreamReader::operator()(const std::string &matId,
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
std::vector<material_t> *materials, std::string *warn,
std::string *err, const char *filename, const char *mtl_basedir,
- bool trianglulate, bool default_vcols_fallback) {
+ bool triangulate, bool default_vcols_fallback) {
attrib->vertices.clear();
attrib->normals.clear();
attrib->texcoords.clear();
@@ -2204,7 +2319,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
MaterialFileReader matFileReader(baseDir);
return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader,
- trianglulate, default_vcols_fallback);
+ triangulate, default_vcols_fallback);
}
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
@@ -2470,7 +2585,8 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
std::string namebuf = parseString(&token);
int newMaterialId = -1;
- std::map<std::string, int>::const_iterator it = material_map.find(namebuf);
+ std::map<std::string, int>::const_iterator it =
+ material_map.find(namebuf);
if (it != material_map.end()) {
newMaterialId = it->second;
} else {
@@ -2485,7 +2601,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// this time.
// just clear `faceGroup` after `exportGroupsToShape()` call.
exportGroupsToShape(&shape, prim_group, tags, material, name,
- triangulate, v);
+ triangulate, v, warn);
prim_group.faceGroup.clear();
material = newMaterialId;
}
@@ -2548,7 +2664,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
if (token[0] == 'g' && IS_SPACE((token[1]))) {
// flush previous face group.
bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
- triangulate, v);
+ triangulate, v, warn);
(void)ret; // return value not used.
if (shape.mesh.indices.size() > 0) {
@@ -2600,7 +2716,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
if (token[0] == 'o' && IS_SPACE((token[1]))) {
// flush previous face group.
bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
- triangulate, v);
+ triangulate, v, warn);
(void)ret; // return value not used.
if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 ||
@@ -2740,7 +2856,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
}
bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
- triangulate, v);
+ triangulate, v, warn);
// exportGroupsToShape return false when `usemtl` is called in the last
// line.
// we also add `shape` to `shapes` when `shape.mesh` has already some
@@ -2880,7 +2996,8 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
std::string namebuf = ss.str();
int newMaterialId = -1;
- std::map<std::string, int>::const_iterator it = material_map.find(namebuf);
+ std::map<std::string, int>::const_iterator it =
+ material_map.find(namebuf);
if (it != material_map.end()) {
newMaterialId = it->second;
} else {