Merge branch 'master' of github.com:syoyo/tinyobjloader

This commit is contained in:
Syoyo Fujita
2017-10-13 02:04:11 +09:00
8 changed files with 171 additions and 60 deletions

View File

@@ -58,7 +58,7 @@ TinyObjLoader is successfully used in ...
* cudabox: CUDA Solid Voxelizer Engine https://github.com/gaspardzoss/cudavox * 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 * 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 * 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) ### Old version(v0.9.x)

View File

@@ -0,0 +1,2 @@
newmtl main
Kd 1 1 1

View File

@@ -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

7
models/norm-texopt.mtl Normal file
View File

@@ -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

7
models/norm-texopt.obj Normal file
View File

@@ -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

View File

@@ -48,7 +48,7 @@ static PyObject* pyLoadObj(PyObject* self, PyObject* args) {
pyshapes = PyDict_New(); pyshapes = PyDict_New();
pymaterials = PyDict_New(); pymaterials = PyDict_New();
pymaterial_indices = PyDict_New(); pymaterial_indices = PyList_New(0);
rtndict = PyDict_New(); rtndict = PyDict_New();
attribobj = PyDict_New(); attribobj = PyDict_New();
@@ -124,53 +124,52 @@ static PyObject* pyLoadObj(PyObject* self, PyObject* args) {
PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj); PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj);
} }
long material_index = 0;
for (std::vector<tinyobj::material_t>::iterator mat = materials.begin(); for (std::vector<tinyobj::material_t>::iterator mat = materials.begin();
mat != materials.end(); mat++) { mat != materials.end(); mat++) {
PyObject* matobj = PyDict_New(); PyObject* matobj = PyDict_New();
PyObject* unknown_parameter = PyDict_New(); PyObject* unknown_parameter = PyDict_New();
for (std::map<std::string, std::string>::iterator p = for (std::map<std::string, std::string>::iterator p =
(*mat).unknown_parameter.begin(); mat->unknown_parameter.begin();
p != (*mat).unknown_parameter.end(); ++p) { p != mat->unknown_parameter.end(); ++p) {
PyDict_SetItemString(unknown_parameter, p->first.c_str(), PyDict_SetItemString(unknown_parameter, p->first.c_str(),
PyUnicode_FromString(p->second.c_str())); PyUnicode_FromString(p->second.c_str()));
} }
PyDict_SetItemString(matobj, "shininess", PyDict_SetItemString(matobj, "shininess",
PyFloat_FromDouble((*mat).shininess)); PyFloat_FromDouble(mat->shininess));
PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior)); PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble(mat->ior));
PyDict_SetItemString(matobj, "dissolve", PyDict_SetItemString(matobj, "dissolve",
PyFloat_FromDouble((*mat).dissolve)); PyFloat_FromDouble(mat->dissolve));
PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum)); PyDict_SetItemString(matobj, "illum", PyLong_FromLong(mat->illum));
PyDict_SetItemString(matobj, "ambient_texname", PyDict_SetItemString(matobj, "ambient_texname",
PyUnicode_FromString((*mat).ambient_texname.c_str())); PyUnicode_FromString(mat->ambient_texname.c_str()));
PyDict_SetItemString(matobj, "diffuse_texname", PyDict_SetItemString(matobj, "diffuse_texname",
PyUnicode_FromString((*mat).diffuse_texname.c_str())); PyUnicode_FromString(mat->diffuse_texname.c_str()));
PyDict_SetItemString(matobj, "specular_texname", PyDict_SetItemString(matobj, "specular_texname",
PyUnicode_FromString((*mat).specular_texname.c_str())); PyUnicode_FromString(mat->specular_texname.c_str()));
PyDict_SetItemString( PyDict_SetItemString(
matobj, "specular_highlight_texname", 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", PyDict_SetItemString(matobj, "bump_texname",
PyUnicode_FromString((*mat).bump_texname.c_str())); PyUnicode_FromString(mat->bump_texname.c_str()));
PyDict_SetItemString( PyDict_SetItemString(
matobj, "displacement_texname", matobj, "displacement_texname",
PyUnicode_FromString((*mat).displacement_texname.c_str())); PyUnicode_FromString(mat->displacement_texname.c_str()));
PyDict_SetItemString(matobj, "alpha_texname", PyDict_SetItemString(matobj, "alpha_texname",
PyUnicode_FromString((*mat).alpha_texname.c_str())); PyUnicode_FromString(mat->alpha_texname.c_str()));
PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient)); PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3(mat->ambient));
PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse)); PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3(mat->diffuse));
PyDict_SetItemString(matobj, "specular", PyDict_SetItemString(matobj, "specular",
pyTupleFromfloat3((*mat).specular)); pyTupleFromfloat3(mat->specular));
PyDict_SetItemString(matobj, "transmittance", PyDict_SetItemString(matobj, "transmittance",
pyTupleFromfloat3((*mat).transmittance)); pyTupleFromfloat3(mat->transmittance));
PyDict_SetItemString(matobj, "emission", PyDict_SetItemString(matobj, "emission",
pyTupleFromfloat3((*mat).emission)); pyTupleFromfloat3(mat->emission));
PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter); PyDict_SetItemString(matobj, "unknown_parameter", unknown_parameter);
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj); PyDict_SetItemString(pymaterials, mat->name.c_str(), matobj);
PyDict_SetItemString(pymaterial_indices, PyLong_FromLong(material_index++), (*mat).name.c_str()); PyList_Append(pymaterial_indices, PyUnicode_FromString(mat->name.c_str()));
} }
PyDict_SetItemString(rtndict, "shapes", pyshapes); PyDict_SetItemString(rtndict, "shapes", pyshapes);

View File

@@ -631,13 +631,14 @@ TEST_CASE("vertex-col-ext", "[Issue144]") {
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::string err; std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/cube-vertexcol.obj", gMtlBasePath); bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/cube-vertexcol.obj", gMtlBasePath);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
PrintInfo(attrib, shapes, materials); //PrintInfo(attrib, shapes, materials);
REQUIRE(true == ret); REQUIRE(true == ret);
REQUIRE((8 * 3) == attrib.colors.size()); 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 + 0]));
REQUIRE(1 == Approx(attrib.colors[3 * 7 + 1])); REQUIRE(1 == Approx(attrib.colors[3 * 7 + 1]));
REQUIRE(1 == Approx(attrib.colors[3 * 7 + 2])); 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());
} }

View File

@@ -101,11 +101,11 @@ namespace tinyobj {
// cube_left | cube_right // cube_left | cube_right
#ifdef TINYOBJLOADER_USE_DOUBLE #ifdef TINYOBJLOADER_USE_DOUBLE
//#pragma message "using double" //#pragma message "using double"
typedef double real_t; typedef double real_t;
#else #else
//#pragma message "using float" //#pragma message "using float"
typedef float real_t; typedef float real_t;
#endif #endif
typedef enum { typedef enum {
@@ -120,7 +120,7 @@ typedef enum {
} texture_type_t; } texture_type_t;
typedef struct { 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 sharpness; // -boost (default 1.0?)
real_t brightness; // base_value in -mm option (default 0) real_t brightness; // base_value in -mm option (default 0)
real_t contrast; // gain_value in -mm option (default 1) real_t contrast; // gain_value in -mm option (default 1)
@@ -366,7 +366,6 @@ namespace tinyobj {
MaterialReader::~MaterialReader() {} MaterialReader::~MaterialReader() {}
struct vertex_index { struct vertex_index {
int v_idx, vt_idx, vn_idx; int v_idx, vt_idx, vn_idx;
vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} 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')) #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
// Make index zero-base, and also support relative index. // Make index zero-base, and also support relative index.
static inline int fixIndex(int idx, int n) { static inline bool fixIndex(int idx, int n, int *ret) {
if (idx > 0) return idx - 1; if (!ret) {
if (idx == 0) return 0; return false;
return n + idx; // negative value = relative }
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) { 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: assemble:
*result = *result = (sign == '+' ? 1 : -1) *
(sign == '+' ? 1 : -1) * (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
(exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) : mantissa); : mantissa);
return true; return true;
fail: fail:
return false; 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, static inline void parseReal2(real_t *x, real_t *y, const char **token,
const double default_x = 0.0, const double default_x = 0.0,
const double default_y = 0.0) { const double default_y = 0.0) {
(*x) = parseReal(token, default_x); (*x) = parseReal(token, default_x);
(*y) = parseReal(token, default_y); (*y) = parseReal(token, default_y);
} }
static inline void parseReal3(real_t *x, real_t *y, real_t *z, const char **token, static inline void parseReal3(real_t *x, real_t *y, real_t *z,
const double default_x = 0.0, const char **token, const double default_x = 0.0,
const double default_y = 0.0, const double default_y = 0.0,
const double default_z = 0.0) { const double default_z = 0.0) {
(*x) = parseReal(token, default_x); (*x) = parseReal(token, default_x);
(*y) = parseReal(token, default_y); (*y) = parseReal(token, default_y);
(*z) = parseReal(token, default_z); (*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 // Parse triples with index offsets: i, i/j/k, i//k, i/j
static vertex_index parseTriple(const char **token, int vsize, int vnsize, static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
int vtsize) { vertex_index *ret) {
if (!ret) {
return false;
}
vertex_index vi(-1); 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"); (*token) += strcspn((*token), "/ \t\r");
if ((*token)[0] != '/') { if ((*token)[0] != '/') {
return vi; (*ret) = vi;
return true;
} }
(*token)++; (*token)++;
// i//k // i//k
if ((*token)[0] == '/') { if ((*token)[0] == '/') {
(*token)++; (*token)++;
vi.vn_idx = fixIndex(atoi((*token)), vnsize); if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
return vi; (*ret) = vi;
return true;
} }
// i/j/k or i/j // 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"); (*token) += strcspn((*token), "/ \t\r");
if ((*token)[0] != '/') { if ((*token)[0] != '/') {
return vi; (*ret) = vi;
return true;
} }
// i/j/k // i/j/k
(*token)++; // skip '/' (*token)++; // skip '/'
vi.vn_idx = fixIndex(atoi((*token)), vnsize); if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) {
return false;
}
(*token) += strcspn((*token), "/ \t\r"); (*token) += strcspn((*token), "/ \t\r");
return vi;
(*ret) = vi;
return true;
} }
// Parse raw triples: i, i/j/k, i//k, i/j // 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]))) { } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) {
token += 3; token += 3;
parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), 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]))) { } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) {
token += 3; token += 3;
parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), 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]))) { } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) {
token += 3; token += 3;
parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), 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]))) { } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) {
token += 5; token += 5;
texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE);
@@ -1571,9 +1607,16 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
face.reserve(3); face.reserve(3);
while (!IS_NEW_LINE(token[0])) { while (!IS_NEW_LINE(token[0])) {
vertex_index vi = parseTriple(&token, static_cast<int>(v.size() / 3), vertex_index vi;
static_cast<int>(vn.size() / 3), if (!parseTriple(&token, static_cast<int>(v.size() / 3),
static_cast<int>(vt.size() / 2)); 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); face.push_back(vi);
size_t n = strspn(token, " \t\r"); size_t n = strspn(token, " \t\r");
token += n; token += n;
@@ -1661,7 +1704,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// flush previous face group. // flush previous face group.
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name, bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
triangulate); triangulate);
(void)ret; // return value not used. (void)ret; // return value not used.
if (shape.mesh.indices.size() > 0) { if (shape.mesh.indices.size() > 0) {
shapes->push_back(shape); shapes->push_back(shape);