Compare commits
14 Commits
group-fix
...
1e2cd27c64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e2cd27c64 | ||
|
|
49726abcf1 | ||
|
|
b29d34f2e1 | ||
|
|
cb085d1fb6 | ||
|
|
b38e97b7ec | ||
|
|
b434c2497f | ||
|
|
94fc413466 | ||
|
|
1c6dbf9bd8 | ||
|
|
88ad575f62 | ||
|
|
5cd30b70e0 | ||
|
|
eb1f395101 | ||
|
|
27bdd547f0 | ||
|
|
75a4bd1d35 | ||
|
|
7c7335c907 |
16
README.md
16
README.md
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
[](https://coveralls.io/github/syoyo/tinyobjloader?branch=master)
|
[](https://coveralls.io/github/syoyo/tinyobjloader?branch=master)
|
||||||
|
|
||||||
http://syoyo.github.io/tinyobjloader/
|
[https://github.com/syoyo/tinyobjloader](https://github.com/syoyo/tinyobjloader)
|
||||||
|
|
||||||
Tiny but powerful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse over 10M polygons with moderate memory and time.
|
Tiny but powerful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse over 10M polygons with moderate memory and time.
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -89,6 +89,7 @@ TinyObjLoader is successfully used in ...
|
|||||||
|
|
||||||
* Group(parse multiple group name)
|
* Group(parse multiple group name)
|
||||||
* Vertex
|
* Vertex
|
||||||
|
* Vertex color(as an extension: https://blender.stackexchange.com/questions/31997/how-can-i-get-vertex-painted-obj-files-to-import-into-blender)
|
||||||
* Texcoord
|
* Texcoord
|
||||||
* Normal
|
* Normal
|
||||||
* Material
|
* Material
|
||||||
@@ -139,6 +140,13 @@ attrib_t::texcoords => 2 floats per vertex
|
|||||||
| u | v | u | v | u | v | u | v | .... | u | v |
|
| u | v | u | v | u | v | u | v | .... | u | v |
|
||||||
+-----------+-----------+-----------+-----------+ +-----------+
|
+-----------+-----------+-----------+-----------+ +-----------+
|
||||||
|
|
||||||
|
attrib_t::colors => 3 floats per vertex(vertex color. optional)
|
||||||
|
|
||||||
|
c[0] c[1] c[2] c[3] c[n-1]
|
||||||
|
+-----------+-----------+-----------+-----------+ +-----------+
|
||||||
|
| x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
|
||||||
|
+-----------+-----------+-----------+-----------+ +-----------+
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Each `shape_t::mesh_t` does not contain vertex data but contains array index to `attrib_t`.
|
Each `shape_t::mesh_t` does not contain vertex data but contains array index to `attrib_t`.
|
||||||
@@ -228,6 +236,10 @@ for (size_t s = 0; s < shapes.size(); s++) {
|
|||||||
tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2];
|
tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2];
|
||||||
tinyobj::real_t tx = attrib.texcoords[2*idx.texcoord_index+0];
|
tinyobj::real_t tx = attrib.texcoords[2*idx.texcoord_index+0];
|
||||||
tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1];
|
tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1];
|
||||||
|
// Optional: vertex colors
|
||||||
|
// tinyobj::real_t red = attrib.colors[3*idx.vertex_index+0];
|
||||||
|
// tinyobj::real_t green = attrib.colors[3*idx.vertex_index+1];
|
||||||
|
// tinyobj::real_t blue = attrib.colors[3*idx.vertex_index+2];
|
||||||
}
|
}
|
||||||
index_offset += fv;
|
index_offset += fv;
|
||||||
|
|
||||||
|
|||||||
@@ -1440,7 +1440,9 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
// std::cout << "mtllib :" << material_filename << std::endl;
|
// std::cout << "mtllib :" << material_filename << std::endl;
|
||||||
|
|
||||||
auto t1 = std::chrono::high_resolution_clock::now();
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
|
if (material_filename.back() == '\r') {
|
||||||
|
material_filename.pop_back();
|
||||||
|
}
|
||||||
std::ifstream ifs(material_filename);
|
std::ifstream ifs(material_filename);
|
||||||
if (ifs.good()) {
|
if (ifs.good()) {
|
||||||
LoadMtl(&material_map, materials, &ifs);
|
LoadMtl(&material_map, materials, &ifs);
|
||||||
@@ -1516,13 +1518,13 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
StackVector<std::thread, 16> workers;
|
StackVector<std::thread, 16> workers;
|
||||||
|
|
||||||
for (size_t t = 0; t < num_threads; t++) {
|
for (size_t t = 0; t < num_threads; t++) {
|
||||||
int material_id = -1; // -1 = default unknown material.
|
|
||||||
workers->push_back(std::thread([&, t]() {
|
workers->push_back(std::thread([&, t]() {
|
||||||
size_t v_count = v_offsets[t];
|
size_t v_count = v_offsets[t];
|
||||||
size_t n_count = n_offsets[t];
|
size_t n_count = n_offsets[t];
|
||||||
size_t t_count = t_offsets[t];
|
size_t t_count = t_offsets[t];
|
||||||
size_t f_count = f_offsets[t];
|
size_t f_count = f_offsets[t];
|
||||||
size_t face_count = face_offsets[t];
|
size_t face_count = face_offsets[t];
|
||||||
|
int material_id = -1; // -1 = default unknown material.
|
||||||
|
|
||||||
for (size_t i = 0; i < commands[t].size(); i++) {
|
for (size_t i = 0; i < commands[t].size(); i++) {
|
||||||
if (commands[t][i].type == COMMAND_EMPTY) {
|
if (commands[t][i].type == COMMAND_EMPTY) {
|
||||||
@@ -1579,7 +1581,19 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
for (size_t t = 0; t < workers->size(); t++) {
|
for (size_t t = 0; t < workers->size(); t++) {
|
||||||
workers[t].join();
|
workers[t].join();
|
||||||
}
|
}
|
||||||
|
if(material_map.size()>1&& num_threads>1) {
|
||||||
|
for (size_t t = 0; t < num_threads; t++) {
|
||||||
|
size_t face_count = face_offsets[t];
|
||||||
|
if (-1 == attrib->material_ids[face_count]) {
|
||||||
|
int prev_material_id = attrib->material_ids[face_count - 1];
|
||||||
|
size_t max_face_offset = (t == num_threads - 1) ? attrib->material_ids.size() : face_offsets[t + 1];
|
||||||
|
for (int i = face_count; i<max_face_offset; ++i) {
|
||||||
|
if (attrib->material_ids[i] != -1) break;
|
||||||
|
attrib->material_ids[i] = prev_material_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
auto t_end = std::chrono::high_resolution_clock::now();
|
auto t_end = std::chrono::high_resolution_clock::now();
|
||||||
ms_merge = t_end - t_start;
|
ms_merge = t_end - t_start;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TINYOBJ_USE_CXX11
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
class timerutil {
|
class timerutil {
|
||||||
public:
|
public:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -63,7 +70,7 @@ class timerutil {
|
|||||||
}
|
}
|
||||||
time_t current() {
|
time_t current() {
|
||||||
struct timeval t;
|
struct timeval t;
|
||||||
gettimeofday(&t, NULL);
|
gettimeofday(&t, tobj_null);
|
||||||
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
|
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +268,7 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TestLoadObj(const char* filename, const char* basepath = NULL,
|
static bool TestLoadObj(const char* filename, const char* basepath = tobj_null,
|
||||||
bool triangulate = true) {
|
bool triangulate = true) {
|
||||||
std::cout << "Loading " << filename << std::endl;
|
std::cout << "Loading " << filename << std::endl;
|
||||||
|
|
||||||
|
|||||||
31
models/cube-vertexcol.obj
Normal file
31
models/cube-vertexcol.obj
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
mtllib cube.mtl
|
||||||
|
|
||||||
|
v 0.000000 2.000000 2.000000 0 0 0
|
||||||
|
v 0.000000 0.000000 2.000000 0 0 1
|
||||||
|
v 2.000000 0.000000 2.000000 0 1 0
|
||||||
|
v 2.000000 2.000000 2.000000 0 1 1
|
||||||
|
v 0.000000 2.000000 0.000000 1 0 0
|
||||||
|
v 0.000000 0.000000 0.000000 1 0 1
|
||||||
|
v 2.000000 0.000000 0.000000 1 1 0
|
||||||
|
v 2.000000 2.000000 0.000000 1 1 1
|
||||||
|
# 8 vertices
|
||||||
|
|
||||||
|
g front cube
|
||||||
|
usemtl white
|
||||||
|
f 1 2 3 4
|
||||||
|
g back cube
|
||||||
|
# expects white material
|
||||||
|
f 8 7 6 5
|
||||||
|
g right cube
|
||||||
|
usemtl red
|
||||||
|
f 4 3 7 8
|
||||||
|
g top cube
|
||||||
|
usemtl white
|
||||||
|
f 5 1 4 8
|
||||||
|
g left cube
|
||||||
|
usemtl green
|
||||||
|
f 5 6 2 1
|
||||||
|
g bottom cube
|
||||||
|
usemtl white
|
||||||
|
f 2 6 7 3
|
||||||
|
# 6 elements
|
||||||
2
models/issue-140-zero-face-idx.mtl
Normal file
2
models/issue-140-zero-face-idx.mtl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
newmtl main
|
||||||
|
Kd 1 1 1
|
||||||
17
models/issue-140-zero-face-idx.obj
Normal file
17
models/issue-140-zero-face-idx.obj
Normal 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
7
models/norm-texopt.mtl
Normal 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
7
models/norm-texopt.obj
Normal 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
|
||||||
28
models/texture-filename-with-whitespace.mtl
Normal file
28
models/texture-filename-with-whitespace.mtl
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
newmtl white
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 1 1 1
|
||||||
|
Ks 0 0 0
|
||||||
|
# filename with white space.
|
||||||
|
map_Kd texture 01.png
|
||||||
|
|
||||||
|
newmtl red
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 1 0 0
|
||||||
|
Ks 0 0 0
|
||||||
|
# texture option + filename with white space.
|
||||||
|
bump -bm 2 bump 01.png
|
||||||
|
|
||||||
|
newmtl green
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 1 0
|
||||||
|
Ks 0 0 0
|
||||||
|
|
||||||
|
newmtl blue
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 0 1
|
||||||
|
Ks 0 0 0
|
||||||
|
|
||||||
|
newmtl light
|
||||||
|
Ka 20 20 20
|
||||||
|
Kd 1 1 1
|
||||||
|
Ks 0 0 0
|
||||||
31
models/texture-filename-with-whitespace.obj
Normal file
31
models/texture-filename-with-whitespace.obj
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
mtllib texture-filename-with-whitespace.mtl
|
||||||
|
|
||||||
|
v 0.000000 2.000000 2.000000
|
||||||
|
v 0.000000 0.000000 2.000000
|
||||||
|
v 2.000000 0.000000 2.000000
|
||||||
|
v 2.000000 2.000000 2.000000
|
||||||
|
v 0.000000 2.000000 0.000000
|
||||||
|
v 0.000000 0.000000 0.000000
|
||||||
|
v 2.000000 0.000000 0.000000
|
||||||
|
v 2.000000 2.000000 0.000000
|
||||||
|
# 8 vertices
|
||||||
|
|
||||||
|
g front cube
|
||||||
|
usemtl white
|
||||||
|
f 1 2 3 4
|
||||||
|
g back cube
|
||||||
|
# expects white material
|
||||||
|
f 8 7 6 5
|
||||||
|
g right cube
|
||||||
|
usemtl red
|
||||||
|
f 4 3 7 8
|
||||||
|
g top cube
|
||||||
|
usemtl white
|
||||||
|
f 5 1 4 8
|
||||||
|
g left cube
|
||||||
|
usemtl green
|
||||||
|
f 5 6 2 1
|
||||||
|
g bottom cube
|
||||||
|
usemtl white
|
||||||
|
f 2 6 7 3
|
||||||
|
# 6 elements
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -625,6 +625,98 @@ TEST_CASE("g_ignored", "[Issue138]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("vertex-col-ext", "[Issue144]") {
|
||||||
|
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/cube-vertexcol.obj", gMtlBasePath);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//PrintInfo(attrib, shapes, materials);
|
||||||
|
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
REQUIRE((8 * 3) == attrib.colors.size());
|
||||||
|
|
||||||
|
REQUIRE(0 == Approx(attrib.colors[3 * 0 + 0]));
|
||||||
|
REQUIRE(0 == Approx(attrib.colors[3 * 0 + 1]));
|
||||||
|
REQUIRE(0 == Approx(attrib.colors[3 * 0 + 2]));
|
||||||
|
|
||||||
|
REQUIRE(0 == Approx(attrib.colors[3 * 1 + 0]));
|
||||||
|
REQUIRE(0 == Approx(attrib.colors[3 * 1 + 1]));
|
||||||
|
REQUIRE(1 == Approx(attrib.colors[3 * 1 + 2]));
|
||||||
|
|
||||||
|
REQUIRE(1 == Approx(attrib.colors[3 * 4 + 0]));
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("texture-name-whitespace", "[Issue145]") {
|
||||||
|
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/texture-filename-with-whitespace.obj", gMtlBasePath);
|
||||||
|
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << "[Issue145] " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
REQUIRE(err.empty());
|
||||||
|
REQUIRE(2 < materials.size());
|
||||||
|
|
||||||
|
REQUIRE(0 == materials[0].diffuse_texname.compare("texture 01.png"));
|
||||||
|
REQUIRE(0 == materials[1].bump_texname.compare("bump 01.png"));
|
||||||
|
REQUIRE(2 == Approx(materials[1].bump_texopt.bump_multiplier));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int
|
int
|
||||||
main(
|
main(
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ THE SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// version 1.1.0 : Support parsing vertex color(#144)
|
||||||
// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138)
|
// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138)
|
||||||
// version 1.0.7 : Support multiple tex options(#126)
|
// version 1.0.7 : Support multiple tex options(#126)
|
||||||
// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124)
|
// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124)
|
||||||
@@ -50,6 +51,32 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
namespace tinyobj {
|
namespace tinyobj {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Please define `TINYOBJ_USE_CXX11` flag when you compile tinyobjloader with C++11 compiler.
|
||||||
|
//
|
||||||
|
#ifdef TINYOBJ_USE_CXX11
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# if _MSC_VER < 1800
|
||||||
|
# error This project needs at least Visual Studio 2013
|
||||||
|
# endif
|
||||||
|
#define tobj_null nullptr
|
||||||
|
#elif __cplusplus <= 199711L
|
||||||
|
# error This project can only be compiled with a compiler that supports C++11
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define tobj_null nullptr
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#else // !TINYOBJ_USE_CXX11
|
||||||
|
#define tobj_null NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ...
|
// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ...
|
||||||
//
|
//
|
||||||
// -blendu on | off # set horizontal texture blending
|
// -blendu on | off # set horizontal texture blending
|
||||||
@@ -100,11 +127,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 {
|
||||||
@@ -119,7 +146,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)
|
||||||
@@ -230,6 +257,7 @@ typedef struct {
|
|||||||
std::vector<real_t> vertices; // 'v'
|
std::vector<real_t> vertices; // 'v'
|
||||||
std::vector<real_t> normals; // 'vn'
|
std::vector<real_t> normals; // 'vn'
|
||||||
std::vector<real_t> texcoords; // 'vt'
|
std::vector<real_t> texcoords; // 'vt'
|
||||||
|
std::vector<real_t> colors; // extension: vertex colors
|
||||||
} attrib_t;
|
} attrib_t;
|
||||||
|
|
||||||
typedef struct callback_t_ {
|
typedef struct callback_t_ {
|
||||||
@@ -257,14 +285,14 @@ typedef struct callback_t_ {
|
|||||||
void (*object_cb)(void *user_data, const char *name);
|
void (*object_cb)(void *user_data, const char *name);
|
||||||
|
|
||||||
callback_t_()
|
callback_t_()
|
||||||
: vertex_cb(NULL),
|
: vertex_cb(tobj_null),
|
||||||
normal_cb(NULL),
|
normal_cb(tobj_null),
|
||||||
texcoord_cb(NULL),
|
texcoord_cb(tobj_null),
|
||||||
index_cb(NULL),
|
index_cb(tobj_null),
|
||||||
usemtl_cb(NULL),
|
usemtl_cb(tobj_null),
|
||||||
mtllib_cb(NULL),
|
mtllib_cb(tobj_null),
|
||||||
group_cb(NULL),
|
group_cb(tobj_null),
|
||||||
object_cb(NULL) {}
|
object_cb(tobj_null) {}
|
||||||
} callback_t;
|
} callback_t;
|
||||||
|
|
||||||
class MaterialReader {
|
class MaterialReader {
|
||||||
@@ -316,7 +344,7 @@ class MaterialStreamReader : public MaterialReader {
|
|||||||
/// or not.
|
/// or not.
|
||||||
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||||
std::vector<material_t> *materials, std::string *err,
|
std::vector<material_t> *materials, std::string *err,
|
||||||
const char *filename, const char *mtl_basedir = NULL,
|
const char *filename, const char *mtl_basedir = tobj_null,
|
||||||
bool triangulate = true);
|
bool triangulate = true);
|
||||||
|
|
||||||
/// Loads .obj from a file with custom user callback.
|
/// Loads .obj from a file with custom user callback.
|
||||||
@@ -326,9 +354,9 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
/// Returns warning and error message into `err`
|
/// Returns warning and error message into `err`
|
||||||
/// See `examples/callback_api/` for how to use this function.
|
/// See `examples/callback_api/` for how to use this function.
|
||||||
bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
||||||
void *user_data = NULL,
|
void *user_data = tobj_null,
|
||||||
MaterialReader *readMatFn = NULL,
|
MaterialReader *readMatFn = tobj_null,
|
||||||
std::string *err = NULL);
|
std::string *err = tobj_null);
|
||||||
|
|
||||||
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
|
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
|
||||||
/// std::istream for materials.
|
/// std::istream for materials.
|
||||||
@@ -336,7 +364,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
/// Returns warning and error message into `err`
|
/// Returns warning and error message into `err`
|
||||||
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||||
std::vector<material_t> *materials, std::string *err,
|
std::vector<material_t> *materials, std::string *err,
|
||||||
std::istream *inStream, MaterialReader *readMatFn = NULL,
|
std::istream *inStream, MaterialReader *readMatFn = tobj_null,
|
||||||
bool triangulate = true);
|
bool triangulate = true);
|
||||||
|
|
||||||
/// Loads materials into std::map
|
/// Loads materials into std::map
|
||||||
@@ -346,6 +374,10 @@ void LoadMtl(std::map<std::string, int> *material_map,
|
|||||||
|
|
||||||
} // namespace tinyobj
|
} // namespace tinyobj
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // TINY_OBJ_LOADER_H_
|
#endif // TINY_OBJ_LOADER_H_
|
||||||
|
|
||||||
#ifdef TINYOBJLOADER_IMPLEMENTATION
|
#ifdef TINYOBJLOADER_IMPLEMENTATION
|
||||||
@@ -362,8 +394,14 @@ void LoadMtl(std::map<std::string, int> *material_map,
|
|||||||
|
|
||||||
namespace tinyobj {
|
namespace tinyobj {
|
||||||
|
|
||||||
MaterialReader::~MaterialReader() {}
|
#ifdef TINYOBJ_USE_CXX11
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MaterialReader::~MaterialReader() {}
|
||||||
|
|
||||||
struct vertex_index {
|
struct vertex_index {
|
||||||
int v_idx, vt_idx, vn_idx;
|
int v_idx, vt_idx, vn_idx;
|
||||||
@@ -428,10 +466,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) {
|
||||||
@@ -584,9 +639,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;
|
||||||
@@ -602,17 +657,30 @@ static inline real_t parseReal(const char **token, double default_value = 0.0) {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool parseReal(const char **token, real_t *out) {
|
||||||
|
(*token) += strspn((*token), " \t");
|
||||||
|
const char *end = (*token) + strcspn((*token), " \t\r");
|
||||||
|
double val;
|
||||||
|
bool ret = tryParseDouble((*token), end, &val);
|
||||||
|
if (ret) {
|
||||||
|
real_t f = static_cast<real_t>(val);
|
||||||
|
(*out) = f;
|
||||||
|
}
|
||||||
|
(*token) = end;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -629,6 +697,23 @@ static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w,
|
|||||||
(*w) = parseReal(token, default_w);
|
(*w) = parseReal(token, default_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extension: parse vertex with colors(6 items)
|
||||||
|
static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, real_t *r,
|
||||||
|
real_t *g, real_t *b,
|
||||||
|
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);
|
||||||
|
|
||||||
|
(*r) = parseReal(token, 1.0);
|
||||||
|
(*g) = parseReal(token, 1.0);
|
||||||
|
(*b) = parseReal(token, 1.0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool parseOnOff(const char **token, bool default_value = true) {
|
static inline bool parseOnOff(const char **token, bool default_value = true) {
|
||||||
(*token) += strspn((*token), " \t");
|
(*token) += strspn((*token), " \t");
|
||||||
const char *end = (*token) + strcspn((*token), " \t\r");
|
const char *end = (*token) + strcspn((*token), " \t\r");
|
||||||
@@ -673,58 +758,80 @@ static inline texture_type_t parseTextureType(
|
|||||||
static tag_sizes parseTagTriple(const char **token) {
|
static tag_sizes parseTagTriple(const char **token) {
|
||||||
tag_sizes ts;
|
tag_sizes ts;
|
||||||
|
|
||||||
|
(*token) += strspn((*token), " \t");
|
||||||
ts.num_ints = atoi((*token));
|
ts.num_ints = atoi((*token));
|
||||||
(*token) += strcspn((*token), "/ \t\r");
|
(*token) += strcspn((*token), "/ \t\r");
|
||||||
if ((*token)[0] != '/') {
|
if ((*token)[0] != '/') {
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
(*token)++;
|
|
||||||
|
|
||||||
|
(*token)++; // Skip '/'
|
||||||
|
|
||||||
|
(*token) += strspn((*token), " \t");
|
||||||
ts.num_reals = atoi((*token));
|
ts.num_reals = atoi((*token));
|
||||||
(*token) += strcspn((*token), "/ \t\r");
|
(*token) += strcspn((*token), "/ \t\r");
|
||||||
if ((*token)[0] != '/') {
|
if ((*token)[0] != '/') {
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
(*token)++;
|
(*token)++; // Skip '/'
|
||||||
|
|
||||||
ts.num_strings = atoi((*token));
|
ts.num_strings = parseInt(token);
|
||||||
(*token) += strcspn((*token), "/ \t\r") + 1;
|
|
||||||
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -813,15 +920,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);
|
||||||
@@ -838,11 +945,18 @@ static bool ParseTextureNameAndOption(std::string *texname,
|
|||||||
parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
|
parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
|
||||||
} else {
|
} else {
|
||||||
// Assume texture filename
|
// Assume texture filename
|
||||||
|
#if 0
|
||||||
size_t len = strcspn(token, " \t\r"); // untile next space
|
size_t len = strcspn(token, " \t\r"); // untile next space
|
||||||
texture_name = std::string(token, token + len);
|
texture_name = std::string(token, token + len);
|
||||||
token += len;
|
token += len;
|
||||||
|
|
||||||
token += strspn(token, " \t"); // skip space
|
token += strspn(token, " \t"); // skip space
|
||||||
|
#else
|
||||||
|
// Read filename until line end to parse filename containing whitespace
|
||||||
|
// TODO(syoyo): Support parsing texture option flag after the filename.
|
||||||
|
texture_name = std::string(token);
|
||||||
|
token += texture_name.length();
|
||||||
|
#endif
|
||||||
|
|
||||||
found_texname = true;
|
found_texname = true;
|
||||||
}
|
}
|
||||||
@@ -1421,6 +1535,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
attrib->vertices.clear();
|
attrib->vertices.clear();
|
||||||
attrib->normals.clear();
|
attrib->normals.clear();
|
||||||
attrib->texcoords.clear();
|
attrib->texcoords.clear();
|
||||||
|
attrib->colors.clear();
|
||||||
shapes->clear();
|
shapes->clear();
|
||||||
|
|
||||||
std::stringstream errss;
|
std::stringstream errss;
|
||||||
@@ -1453,6 +1568,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
std::vector<real_t> v;
|
std::vector<real_t> v;
|
||||||
std::vector<real_t> vn;
|
std::vector<real_t> vn;
|
||||||
std::vector<real_t> vt;
|
std::vector<real_t> vt;
|
||||||
|
std::vector<real_t> vc;
|
||||||
std::vector<tag_t> tags;
|
std::vector<tag_t> tags;
|
||||||
std::vector<std::vector<vertex_index> > faceGroup;
|
std::vector<std::vector<vertex_index> > faceGroup;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -1495,10 +1611,15 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
real_t x, y, z;
|
real_t x, y, z;
|
||||||
parseReal3(&x, &y, &z, &token);
|
real_t r, g, b;
|
||||||
|
parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token);
|
||||||
v.push_back(x);
|
v.push_back(x);
|
||||||
v.push_back(y);
|
v.push_back(y);
|
||||||
v.push_back(z);
|
v.push_back(z);
|
||||||
|
|
||||||
|
vc.push_back(r);
|
||||||
|
vc.push_back(g);
|
||||||
|
vc.push_back(b);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1532,9 +1653,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;
|
||||||
@@ -1622,7 +1750,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);
|
||||||
@@ -1680,33 +1808,25 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
tag_t tag;
|
tag_t tag;
|
||||||
|
|
||||||
token += 2;
|
token += 2;
|
||||||
std::stringstream ss;
|
|
||||||
ss << token;
|
|
||||||
tag.name = ss.str();
|
|
||||||
|
|
||||||
token += tag.name.size() + 1;
|
tag.name = parseString(&token);
|
||||||
|
|
||||||
tag_sizes ts = parseTagTriple(&token);
|
tag_sizes ts = parseTagTriple(&token);
|
||||||
|
|
||||||
tag.intValues.resize(static_cast<size_t>(ts.num_ints));
|
tag.intValues.resize(static_cast<size_t>(ts.num_ints));
|
||||||
|
|
||||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
|
||||||
tag.intValues[i] = atoi(token);
|
tag.intValues[i] = parseInt(&token);
|
||||||
token += strcspn(token, "/ \t\r") + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
|
tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
|
||||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
|
||||||
tag.floatValues[i] = parseReal(&token);
|
tag.floatValues[i] = parseReal(&token);
|
||||||
token += strcspn(token, "/ \t\r") + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
|
tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
|
||||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
|
for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
|
||||||
std::stringstream sstr;
|
tag.stringValues[i] = parseString(&token);
|
||||||
sstr << token;
|
|
||||||
tag.stringValues[i] = sstr.str();
|
|
||||||
token += tag.stringValues[i].size() + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tags.push_back(tag);
|
tags.push_back(tag);
|
||||||
@@ -1733,6 +1853,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
attrib->vertices.swap(v);
|
attrib->vertices.swap(v);
|
||||||
attrib->normals.swap(vn);
|
attrib->normals.swap(vn);
|
||||||
attrib->texcoords.swap(vt);
|
attrib->texcoords.swap(vt);
|
||||||
|
attrib->colors.swap(vc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1785,6 +1906,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
// vertex
|
// vertex
|
||||||
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
|
// TODO(syoyo): Support parsing vertex color extension.
|
||||||
real_t x, y, z, w; // w is optional. default = 1.0
|
real_t x, y, z, w; // w is optional. default = 1.0
|
||||||
parseV(&x, &y, &z, &w, &token);
|
parseV(&x, &y, &z, &w, &token);
|
||||||
if (callback.vertex_cb) {
|
if (callback.vertex_cb) {
|
||||||
@@ -1945,7 +2067,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
static_cast<int>(names_out.size()));
|
static_cast<int>(names_out.size()));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
callback.group_cb(user_data, NULL, 0);
|
callback.group_cb(user_data, tobj_null, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2015,6 +2137,11 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace tinyobj
|
} // namespace tinyobj
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user