diff options
author | Syoyo Fujita <syoyo@lighttransport.com> | 2017-10-13 02:04:11 +0900 |
---|---|---|
committer | Syoyo Fujita <syoyo@lighttransport.com> | 2017-10-13 02:04:11 +0900 |
commit | 1c6dbf9bd8f8012512afd3c0ccd91d60865115c5 (patch) | |
tree | 46b4522afff80a95deeeb5ffee4fa47fda75bb6d | |
parent | 88ad575f6247a215bda2a8938bc0f6e41d113ea4 (diff) | |
parent | 5cd30b70e0a8d1d948aaa4c663f9adfcc018359b (diff) | |
download | tinyobjloader-1c6dbf9bd8f8012512afd3c0ccd91d60865115c5.tar.gz |
Merge branch 'master' of github.com:syoyo/tinyobjloader
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | models/issue-140-zero-face-idx.mtl | 2 | ||||
-rw-r--r-- | models/issue-140-zero-face-idx.obj | 17 | ||||
-rw-r--r-- | models/norm-texopt.mtl | 7 | ||||
-rw-r--r-- | models/norm-texopt.obj | 7 | ||||
-rw-r--r-- | python/main.cpp | 43 | ||||
-rw-r--r-- | tests/tester.cc | 38 | ||||
-rw-r--r-- | tiny_obj_loader.h | 115 |
8 files changed, 171 insertions, 60 deletions
@@ -58,7 +58,7 @@ TinyObjLoader is successfully used in ... * cudabox: CUDA Solid Voxelizer Engine https://github.com/gaspardzoss/cudavox * Drake: A planning, control, and analysis toolbox for nonlinear dynamical systems https://github.com/RobotLocomotion/drake * VFPR - a Vulkan Forward Plus Renderer : https://github.com/WindyDarian/Vulkan-Forward-Plus-Renderer -* Your project here! +* Your project here! (Letting us know via github issue is welcome!) ### Old version(v0.9.x) diff --git a/models/issue-140-zero-face-idx.mtl b/models/issue-140-zero-face-idx.mtl new file mode 100644 index 0000000..990a345 --- /dev/null +++ b/models/issue-140-zero-face-idx.mtl @@ -0,0 +1,2 @@ +newmtl main +Kd 1 1 1 diff --git a/models/issue-140-zero-face-idx.obj b/models/issue-140-zero-face-idx.obj new file mode 100644 index 0000000..21a6060 --- /dev/null +++ b/models/issue-140-zero-face-idx.obj @@ -0,0 +1,17 @@ +mtllib issue-140-zero-face-idx.mtl + +v -0.5 -0.5 0 +v 0.5 -0.5 0 +v 0.5 0.5 0 +v -0.5 0.5 0 + +vt 0 0 0 +vt 1 0 0 +vt 1 1 0 +vt 0 1 0 + +vn 0 0 -1 + +usemtl main +f 0/0/0 1/1/0 3/3/0 +f 1/1/0 3/3/0 2/2/0 diff --git a/models/norm-texopt.mtl b/models/norm-texopt.mtl new file mode 100644 index 0000000..e2d4a2c --- /dev/null +++ b/models/norm-texopt.mtl @@ -0,0 +1,7 @@ +newmtl default +Ka 0 0 0 +Kd 0 0 0 +Ks 0 0 0 +Kt 0.1 0.2 0.3 +norm -bm 3 normalmap.jpg + diff --git a/models/norm-texopt.obj b/models/norm-texopt.obj new file mode 100644 index 0000000..babe94d --- /dev/null +++ b/models/norm-texopt.obj @@ -0,0 +1,7 @@ +mtllib norm-texopt.mtl +o Test +v 1.864151 -1.219172 -5.532511 +v 0.575869 -0.666304 5.896140 +v 0.940448 1.000000 -1.971128 +usemtl default +f 1 2 3 diff --git a/python/main.cpp b/python/main.cpp index 9e266c1..4f1d0e0 100644 --- a/python/main.cpp +++ b/python/main.cpp @@ -48,7 +48,7 @@ static PyObject* pyLoadObj(PyObject* self, PyObject* args) { pyshapes = PyDict_New(); pymaterials = PyDict_New(); - pymaterial_indices = PyDict_New(); + pymaterial_indices = PyList_New(0); rtndict = PyDict_New(); attribobj = PyDict_New(); @@ -124,53 +124,52 @@ static PyObject* pyLoadObj(PyObject* self, PyObject* args) { PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj); } - long material_index = 0; for (std::vector<tinyobj::material_t>::iterator mat = materials.begin(); mat != materials.end(); mat++) { PyObject* matobj = PyDict_New(); PyObject* unknown_parameter = PyDict_New(); for (std::map<std::string, std::string>::iterator p = - (*mat).unknown_parameter.begin(); - p != (*mat).unknown_parameter.end(); ++p) { + mat->unknown_parameter.begin(); + p != mat->unknown_parameter.end(); ++p) { PyDict_SetItemString(unknown_parameter, p->first.c_str(), PyUnicode_FromString(p->second.c_str())); } PyDict_SetItemString(matobj, "shininess", - PyFloat_FromDouble((*mat).shininess)); - PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior)); + PyFloat_FromDouble(mat->shininess)); + PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble(mat->ior)); PyDict_SetItemString(matobj, "dissolve", - PyFloat_FromDouble((*mat).dissolve)); - PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum)); + PyFloat_FromDouble(mat->dissolve)); + PyDict_SetItemString(matobj, "illum", PyLong_FromLong(mat->illum)); PyDict_SetItemString(matobj, "ambient_texname", - PyUnicode_FromString((*mat).ambient_texname.c_str())); + PyUnicode_FromString(mat->ambient_texname.c_str())); PyDict_SetItemString(matobj, "diffuse_texname", - PyUnicode_FromString((*mat).diffuse_texname.c_str())); + PyUnicode_FromString(mat->diffuse_texname.c_str())); PyDict_SetItemString(matobj, "specular_texname", - PyUnicode_FromString((*mat).specular_texname.c_str())); + PyUnicode_FromString(mat->specular_texname.c_str())); PyDict_SetItemString( matobj, "specular_highlight_texname", - PyUnicode_FromString((*mat).specular_highlight_texname.c_str())); + PyUnicode_FromString(mat->specular_highlight_texname.c_str())); PyDict_SetItemString(matobj, "bump_texname", - PyUnicode_FromString((*mat).bump_texname.c_str())); + PyUnicode_FromString(mat->bump_texname.c_str())); PyDict_SetItemString( matobj, "displacement_texname", - PyUnicode_FromString((*mat).displacement_texname.c_str())); + PyUnicode_FromString(mat->displacement_texname.c_str())); PyDict_SetItemString(matobj, "alpha_texname", - PyUnicode_FromString((*mat).alpha_texname.c_str())); - PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient)); - PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse)); + PyUnicode_FromString(mat->alpha_texname.c_str())); + PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3(mat->ambient)); + PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3(mat->diffuse)); PyDict_SetItemString(matobj, "specular", - pyTupleFromfloat3((*mat).specular)); + pyTupleFromfloat3(mat->specular)); PyDict_SetItemString(matobj, "transmittance", - pyTupleFromfloat3((*mat).transmittance)); + pyTupleFromfloat3(mat->transmittance)); PyDict_SetItemString(matobj, "emission", - pyTupleFromfloat3((*mat).emission)); + pyTupleFromfloat3(mat->emission)); PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter); - PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj); - PyDict_SetItemString(pymaterial_indices, PyLong_FromLong(material_index++), (*mat).name.c_str()); + PyDict_SetItemString(pymaterials, mat->name.c_str(), matobj); + PyList_Append(pymaterial_indices, PyUnicode_FromString(mat->name.c_str())); } PyDict_SetItemString(rtndict, "shapes", pyshapes); diff --git a/tests/tester.cc b/tests/tester.cc index 83b1df5..811dfbf 100644 --- a/tests/tester.cc +++ b/tests/tester.cc @@ -631,13 +631,14 @@ TEST_CASE("vertex-col-ext", "[Issue144]") { std::vector<tinyobj::material_t> materials; std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/cube-vertexcol.obj", gMtlBasePath); if (!err.empty()) { std::cerr << err << std::endl; } - PrintInfo(attrib, shapes, materials); + //PrintInfo(attrib, shapes, materials); REQUIRE(true == ret); REQUIRE((8 * 3) == attrib.colors.size()); @@ -655,6 +656,41 @@ TEST_CASE("vertex-col-ext", "[Issue144]") { REQUIRE(1 == Approx(attrib.colors[3 * 7 + 0])); REQUIRE(1 == Approx(attrib.colors[3 * 7 + 1])); REQUIRE(1 == Approx(attrib.colors[3 * 7 + 2])); +} + +TEST_CASE("norm_texopts", "[norm]") { + tinyobj::attrib_t attrib; + std::vector<tinyobj::shape_t> shapes; + std::vector<tinyobj::material_t> materials; + + std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/norm-texopt.obj", gMtlBasePath); + + if (!err.empty()) { + std::cerr << err << std::endl; + } + + REQUIRE(true == ret); + REQUIRE(1 == shapes.size()); + REQUIRE(1 == materials.size()); + REQUIRE(3.0 == Approx(materials[0].normal_texopt.bump_multiplier)); + +} + +TEST_CASE("zero-face-idx-value", "[Issue140]") { + tinyobj::attrib_t attrib; + std::vector<tinyobj::shape_t> shapes; + std::vector<tinyobj::material_t> materials; + + std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-140-zero-face-idx.obj", gMtlBasePath); + + + if (!err.empty()) { + std::cerr << err << std::endl; + } + REQUIRE(false == ret); + REQUIRE(!err.empty()); } diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 3d02e8d..591d236 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -101,11 +101,11 @@ namespace tinyobj { // cube_left | cube_right #ifdef TINYOBJLOADER_USE_DOUBLE - //#pragma message "using double" - typedef double real_t; +//#pragma message "using double" +typedef double real_t; #else - //#pragma message "using float" - typedef float real_t; +//#pragma message "using float" +typedef float real_t; #endif typedef enum { @@ -120,7 +120,7 @@ typedef enum { } texture_type_t; typedef struct { - texture_type_t type; // -type (default TEXTURE_TYPE_NONE) + texture_type_t type; // -type (default TEXTURE_TYPE_NONE) real_t sharpness; // -boost (default 1.0?) real_t brightness; // base_value in -mm option (default 0) real_t contrast; // gain_value in -mm option (default 1) @@ -366,7 +366,6 @@ namespace tinyobj { MaterialReader::~MaterialReader() {} - struct vertex_index { int v_idx, vt_idx, vn_idx; vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} @@ -430,10 +429,27 @@ static std::istream &safeGetline(std::istream &is, std::string &t) { #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) // Make index zero-base, and also support relative index. -static inline int fixIndex(int idx, int n) { - if (idx > 0) return idx - 1; - if (idx == 0) return 0; - return n + idx; // negative value = relative +static inline bool fixIndex(int idx, int n, int *ret) { + if (!ret) { + return false; + } + + if (idx > 0) { + (*ret) = idx - 1; + return true; + } + + if (idx == 0) { + // zero is not allowed according to the spec. + return false; + } + + if (idx < 0) { + (*ret) = n + idx; // negative value = relative + return true; + } + + return false; // never reach here. } static inline std::string parseString(const char **token) { @@ -586,9 +602,9 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) { } assemble: - *result = - (sign == '+' ? 1 : -1) * - (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa); + *result = (sign == '+' ? 1 : -1) * + (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) + : mantissa); return true; fail: return false; @@ -618,16 +634,16 @@ static inline bool parseReal(const char **token, real_t *out) { } static inline void parseReal2(real_t *x, real_t *y, const char **token, - const double default_x = 0.0, - const double default_y = 0.0) { + const double default_x = 0.0, + const double default_y = 0.0) { (*x) = parseReal(token, default_x); (*y) = parseReal(token, default_y); } -static inline void parseReal3(real_t *x, real_t *y, real_t *z, const char **token, - const double default_x = 0.0, - const double default_y = 0.0, - const double default_z = 0.0) { +static inline void parseReal3(real_t *x, real_t *y, real_t *z, + const char **token, const double default_x = 0.0, + const double default_y = 0.0, + const double default_z = 0.0) { (*x) = parseReal(token, default_x); (*y) = parseReal(token, default_y); (*z) = parseReal(token, default_z); @@ -726,37 +742,57 @@ static tag_sizes parseTagTriple(const char **token) { } // Parse triples with index offsets: i, i/j/k, i//k, i/j -static vertex_index parseTriple(const char **token, int vsize, int vnsize, - int vtsize) { +static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, + vertex_index *ret) { + if (!ret) { + return false; + } + vertex_index vi(-1); - vi.v_idx = fixIndex(atoi((*token)), vsize); + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); if ((*token)[0] != '/') { - return vi; + (*ret) = vi; + return true; } (*token)++; // i//k if ((*token)[0] == '/') { (*token)++; - vi.vn_idx = fixIndex(atoi((*token)), vnsize); + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } (*token) += strcspn((*token), "/ \t\r"); - return vi; + (*ret) = vi; + return true; } // i/j/k or i/j - vi.vt_idx = fixIndex(atoi((*token)), vtsize); + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); if ((*token)[0] != '/') { - return vi; + (*ret) = vi; + return true; } // i/j/k (*token)++; // skip '/' - vi.vn_idx = fixIndex(atoi((*token)), vnsize); + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { + return false; + } (*token) += strcspn((*token), "/ \t\r"); - return vi; + + (*ret) = vi; + + return true; } // Parse raw triples: i, i/j/k, i//k, i/j @@ -845,15 +881,15 @@ static bool ParseTextureNameAndOption(std::string *texname, } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), - &(texopt->origin_offset[2]), &token); + &(texopt->origin_offset[2]), &token); } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), - &token, 1.0, 1.0, 1.0); + &token, 1.0, 1.0, 1.0); } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { token += 3; parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), - &(texopt->turbulence[2]), &token); + &(texopt->turbulence[2]), &token); } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { token += 5; texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); @@ -1571,9 +1607,16 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, face.reserve(3); while (!IS_NEW_LINE(token[0])) { - vertex_index vi = parseTriple(&token, static_cast<int>(v.size() / 3), - static_cast<int>(vn.size() / 3), - static_cast<int>(vt.size() / 2)); + vertex_index vi; + if (!parseTriple(&token, static_cast<int>(v.size() / 3), + static_cast<int>(vn.size() / 3), + static_cast<int>(vt.size() / 2), &vi)) { + if (err) { + (*err) = "Failed parse `f' line(e.g. zero value for face index).\n"; + } + return false; + } + face.push_back(vi); size_t n = strspn(token, " \t\r"); token += n; @@ -1661,7 +1704,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, // flush previous face group. bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, triangulate); - (void)ret; // return value not used. + (void)ret; // return value not used. if (shape.mesh.indices.size() > 0) { shapes->push_back(shape); |