Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc42bc47ad | ||
|
|
31611161df | ||
|
|
21c93c51ed | ||
|
|
b48d363dd2 | ||
|
|
0f00a3b3e8 | ||
|
|
ab10b76eda | ||
|
|
cf52401ca7 |
177
README.md
177
README.md
@@ -13,7 +13,7 @@ tinyobjloader
|
|||||||
|
|
||||||
http://syoyo.github.io/tinyobjloader/
|
http://syoyo.github.io/tinyobjloader/
|
||||||
|
|
||||||
Tiny but poweful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse 10M over 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 10M over polygons with moderate memory and time.
|
||||||
|
|
||||||
`tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-)
|
`tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-)
|
||||||
|
|
||||||
@@ -50,14 +50,14 @@ Use case
|
|||||||
TinyObjLoader is successfully used in ...
|
TinyObjLoader is successfully used in ...
|
||||||
|
|
||||||
* bullet3 https://github.com/erwincoumans/bullet3
|
* bullet3 https://github.com/erwincoumans/bullet3
|
||||||
* pbrt-v2 https://https://github.com/mmp/pbrt-v2
|
* pbrt-v2 https://github.com/mmp/pbrt-v2
|
||||||
* OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01
|
* OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01
|
||||||
* mallie https://lighttransport.github.io/mallie
|
* mallie https://lighttransport.github.io/mallie
|
||||||
* IBLBaker (Image Based Lighting Baker). http://www.derkreature.com/iblbaker/
|
* IBLBaker (Image Based Lighting Baker). http://www.derkreature.com/iblbaker/
|
||||||
* Stanford CS148 http://web.stanford.edu/class/cs148/assignments/assignment3.pdf
|
* Stanford CS148 http://web.stanford.edu/class/cs148/assignments/assignment3.pdf
|
||||||
* Awesome Bump http://awesomebump.besaba.com/about/
|
* Awesome Bump http://awesomebump.besaba.com/about/
|
||||||
* sdlgl3-wavefront OpenGL .obj viewer https://github.com/chrisliebert/sdlgl3-wavefront
|
* sdlgl3-wavefront OpenGL .obj viewer https://github.com/chrisliebert/sdlgl3-wavefront
|
||||||
* pbrt-v3 https://https://github.com/mmp/pbrt-v3
|
* pbrt-v3 https://github.com/mmp/pbrt-v3
|
||||||
* cocos2d-x https://github.com/cocos2d/cocos2d-x/
|
* cocos2d-x https://github.com/cocos2d/cocos2d-x/
|
||||||
* Android Vulkan demo https://github.com/SaschaWillems/Vulkan
|
* Android Vulkan demo https://github.com/SaschaWillems/Vulkan
|
||||||
* Your project here!
|
* Your project here!
|
||||||
@@ -88,106 +88,107 @@ Usage
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
TinyObjLoader triangulate input .obj by default.
|
TinyObjLoader triangulate input .obj by default.
|
||||||
|
```c++
|
||||||
|
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
|
||||||
|
#include "tiny_obj_loader.h"
|
||||||
|
|
||||||
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
|
std::string inputfile = "cornell_box.obj";
|
||||||
#include "tiny_obj_loader.h"
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
|
||||||
std::string inputfile = "cornell_box.obj";
|
std::string err;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str());
|
||||||
std::vector<tinyobj::material_t> materials;
|
|
||||||
|
|
||||||
std::string err;
|
if (!err.empty()) { // `err` may contain warning message.
|
||||||
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str());
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (!err.empty()) { // `err` may contain warning message.
|
if (!ret) {
|
||||||
std::cerr << err << std::endl;
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||||
exit(1);
|
std::cout << "# of materials : " << materials.size() << std::endl;
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
std::cout << "# of materials : " << materials.size() << std::endl;
|
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
||||||
|
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
||||||
|
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
||||||
|
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||||
|
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||||
|
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < shapes.size(); i++) {
|
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
||||||
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
assert((shapes[i].mesh.positions.size() % 3) == 0);
|
||||||
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
||||||
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
shapes[i].mesh.positions[3*v+0],
|
||||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
shapes[i].mesh.positions[3*v+1],
|
||||||
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
|
shapes[i].mesh.positions[3*v+2]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
|
||||||
assert((shapes[i].mesh.positions.size() % 3) == 0);
|
|
||||||
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
|
||||||
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
|
||||||
shapes[i].mesh.positions[3*v+0],
|
|
||||||
shapes[i].mesh.positions[3*v+1],
|
|
||||||
shapes[i].mesh.positions[3*v+2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < materials.size(); i++) {
|
|
||||||
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
|
|
||||||
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
|
|
||||||
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
|
|
||||||
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
|
|
||||||
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
|
|
||||||
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
|
|
||||||
printf(" material.Ns = %f\n", materials[i].shininess);
|
|
||||||
printf(" material.Ni = %f\n", materials[i].ior);
|
|
||||||
printf(" material.dissolve = %f\n", materials[i].dissolve);
|
|
||||||
printf(" material.illum = %d\n", materials[i].illum);
|
|
||||||
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
|
|
||||||
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
|
|
||||||
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
|
|
||||||
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
|
|
||||||
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
|
|
||||||
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
|
|
||||||
for (; it != itEnd; it++) {
|
|
||||||
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < materials.size(); i++) {
|
||||||
|
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
|
||||||
|
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
|
||||||
|
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
|
||||||
|
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
|
||||||
|
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
|
||||||
|
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
|
||||||
|
printf(" material.Ns = %f\n", materials[i].shininess);
|
||||||
|
printf(" material.Ni = %f\n", materials[i].ior);
|
||||||
|
printf(" material.dissolve = %f\n", materials[i].dissolve);
|
||||||
|
printf(" material.illum = %d\n", materials[i].illum);
|
||||||
|
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
|
||||||
|
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
|
||||||
|
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
|
||||||
|
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
|
||||||
|
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
|
||||||
|
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
|
||||||
|
for (; it != itEnd; it++) {
|
||||||
|
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Reading .obj without triangulation. Use `num_vertices[i]` to iterate over faces(indices). `num_vertices[i]` stores the number of vertices for ith face.
|
Reading .obj without triangulation. Use `num_vertices[i]` to iterate over faces(indices). `num_vertices[i]` stores the number of vertices for ith face.
|
||||||
|
```c++
|
||||||
|
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
|
||||||
|
#include "tiny_obj_loader.h"
|
||||||
|
|
||||||
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
|
std::string inputfile = "cornell_box.obj";
|
||||||
#include "tiny_obj_loader.h"
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
|
||||||
std::string inputfile = "cornell_box.obj";
|
std::string err;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
bool triangulate = false;
|
||||||
std::vector<tinyobj::material_t> materials;
|
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str(), triangulate);
|
||||||
|
|
||||||
std::string err;
|
if (!err.empty()) { // `err` may contain warning message.
|
||||||
bool triangulate = false;
|
std::cerr << err << std::endl;
|
||||||
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str(), triangulate);
|
}
|
||||||
|
|
||||||
if (!err.empty()) { // `err` may contain warning message.
|
if (!ret) {
|
||||||
std::cerr << err << std::endl;
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < shapes.size(); i++) {
|
size_t indexOffset = 0;
|
||||||
|
for (size_t n = 0; n < shapes[i].mesh.num_vertices.size(); n++) {
|
||||||
size_t indexOffset = 0;
|
int ngon = shapes[i].mesh.num_vertices[n];
|
||||||
for (size_t n = 0; n < shapes[i].mesh.num_vertices.size(); n++) {
|
for (size_t f = 0; f < ngon; f++) {
|
||||||
int ngon = shapes[i].mesh.num_vertices[n];
|
unsigend int v = shapes[i].mesh.indices[indexOffset + f];
|
||||||
for (size_t f = 0; f < ngon; f++) {
|
printf(" face[%ld] v[%ld] = (%f, %f, %f)\n", n,
|
||||||
unsigend int v = shapes[i].mesh.indices[indexOffset + f];
|
shapes[i].mesh.positions[3*v+0],
|
||||||
printf(" face[%ld] v[%ld] = (%f, %f, %f)\n", n,
|
shapes[i].mesh.positions[3*v+1],
|
||||||
shapes[i].mesh.positions[3*v+0],
|
shapes[i].mesh.positions[3*v+2]);
|
||||||
shapes[i].mesh.positions[3*v+1],
|
|
||||||
shapes[i].mesh.positions[3*v+2]);
|
|
||||||
|
|
||||||
}
|
|
||||||
indexOffset += ngon;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
indexOffset += ngon;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
1
test.cc
1
test.cc
@@ -139,6 +139,7 @@ TestLoadObj(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
printf("Failed to load/parse .obj.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// version 0.9.20: Fixes creating per-face material using `usemtl`(#68)
|
||||||
// version 0.9.17: Support n-polygon and crease tag(OpenSubdiv extension)
|
// version 0.9.17: Support n-polygon and crease tag(OpenSubdiv extension)
|
||||||
// version 0.9.16: Make tinyobjloader header-only
|
// version 0.9.16: Make tinyobjloader header-only
|
||||||
// version 0.9.15: Change API to handle no mtl file case correctly(#58)
|
// version 0.9.15: Change API to handle no mtl file case correctly(#58)
|
||||||
@@ -205,11 +206,9 @@ struct obj_shape {
|
|||||||
std::vector<float> vt;
|
std::vector<float> vt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool isSpace(const char c) { return (c == ' ') || (c == '\t'); }
|
#define IS_SPACE( x ) ( ( (x) == ' ') || ( (x) == '\t') )
|
||||||
|
#define IS_DIGIT( x ) ( (unsigned int)( (x) - '0' ) < (unsigned int)10 )
|
||||||
static inline bool isNewLine(const char c) {
|
#define IS_NEW_LINE( x ) ( ( (x) == '\r') || ( (x) == '\n') || ( (x) == '\0') )
|
||||||
return (c == '\r') || (c == '\n') || (c == '\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 int fixIndex(int idx, int n) {
|
||||||
@@ -297,13 +296,13 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
|
|||||||
if (*curr == '+' || *curr == '-') {
|
if (*curr == '+' || *curr == '-') {
|
||||||
sign = *curr;
|
sign = *curr;
|
||||||
curr++;
|
curr++;
|
||||||
} else if (isdigit(*curr)) { /* Pass through. */
|
} else if (IS_DIGIT(*curr)) { /* Pass through. */
|
||||||
} else {
|
} else {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the integer part.
|
// Read the integer part.
|
||||||
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
|
while ((end_not_reached = (curr != s_end)) && IS_DIGIT(*curr)) {
|
||||||
mantissa *= 10;
|
mantissa *= 10;
|
||||||
mantissa += static_cast<int>(*curr - 0x30);
|
mantissa += static_cast<int>(*curr - 0x30);
|
||||||
curr++;
|
curr++;
|
||||||
@@ -321,7 +320,7 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
|
|||||||
if (*curr == '.') {
|
if (*curr == '.') {
|
||||||
curr++;
|
curr++;
|
||||||
read = 1;
|
read = 1;
|
||||||
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
|
while ((end_not_reached = (curr != s_end)) && IS_DIGIT(*curr)) {
|
||||||
// NOTE: Don't use powf here, it will absolutely murder precision.
|
// NOTE: Don't use powf here, it will absolutely murder precision.
|
||||||
mantissa += static_cast<int>(*curr - 0x30) * pow(10.0, -read);
|
mantissa += static_cast<int>(*curr - 0x30) * pow(10.0, -read);
|
||||||
read++;
|
read++;
|
||||||
@@ -342,14 +341,14 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
|
|||||||
if ((end_not_reached = (curr != s_end)) && (*curr == '+' || *curr == '-')) {
|
if ((end_not_reached = (curr != s_end)) && (*curr == '+' || *curr == '-')) {
|
||||||
exp_sign = *curr;
|
exp_sign = *curr;
|
||||||
curr++;
|
curr++;
|
||||||
} else if (isdigit(*curr)) { /* Pass through. */
|
} else if (IS_DIGIT(*curr)) { /* Pass through. */
|
||||||
} else {
|
} else {
|
||||||
// Empty E is not allowed.
|
// Empty E is not allowed.
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
read = 0;
|
read = 0;
|
||||||
while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) {
|
while ((end_not_reached = (curr != s_end)) && IS_DIGIT(*curr)) {
|
||||||
exponent *= 10;
|
exponent *= 10;
|
||||||
exponent += static_cast<int>(*curr - 0x30);
|
exponent += static_cast<int>(*curr - 0x30);
|
||||||
curr++;
|
curr++;
|
||||||
@@ -625,7 +624,7 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
continue; // comment line
|
continue; // comment line
|
||||||
|
|
||||||
// new mtl
|
// new mtl
|
||||||
if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) {
|
if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
|
||||||
// flush previous material.
|
// flush previous material.
|
||||||
if (!material.name.empty()) {
|
if (!material.name.empty()) {
|
||||||
material_map.insert(std::pair<std::string, int>(
|
material_map.insert(std::pair<std::string, int>(
|
||||||
@@ -649,7 +648,7 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ambient
|
// ambient
|
||||||
if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) {
|
if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
@@ -660,7 +659,7 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// diffuse
|
// diffuse
|
||||||
if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) {
|
if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
@@ -671,7 +670,7 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// specular
|
// specular
|
||||||
if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) {
|
if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
@@ -682,7 +681,7 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transmittance
|
// transmittance
|
||||||
if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) {
|
if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
@@ -693,14 +692,14 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ior(index of refraction)
|
// ior(index of refraction)
|
||||||
if (token[0] == 'N' && token[1] == 'i' && isSpace((token[2]))) {
|
if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
material.ior = parseFloat(token);
|
material.ior = parseFloat(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// emission
|
// emission
|
||||||
if (token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) {
|
if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
@@ -711,26 +710,26 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shininess
|
// shininess
|
||||||
if (token[0] == 'N' && token[1] == 's' && isSpace(token[2])) {
|
if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) {
|
||||||
token += 2;
|
token += 2;
|
||||||
material.shininess = parseFloat(token);
|
material.shininess = parseFloat(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// illum model
|
// illum model
|
||||||
if (0 == strncmp(token, "illum", 5) && isSpace(token[5])) {
|
if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) {
|
||||||
token += 6;
|
token += 6;
|
||||||
material.illum = parseInt(token);
|
material.illum = parseInt(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dissolve
|
// dissolve
|
||||||
if ((token[0] == 'd' && isSpace(token[1]))) {
|
if ((token[0] == 'd' && IS_SPACE(token[1]))) {
|
||||||
token += 1;
|
token += 1;
|
||||||
material.dissolve = parseFloat(token);
|
material.dissolve = parseFloat(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) {
|
if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
|
||||||
token += 2;
|
token += 2;
|
||||||
// Invert value of Tr(assume Tr is in range [0, 1])
|
// Invert value of Tr(assume Tr is in range [0, 1])
|
||||||
material.dissolve = 1.0f - parseFloat(token);
|
material.dissolve = 1.0f - parseFloat(token);
|
||||||
@@ -738,56 +737,56 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ambient texture
|
// ambient texture
|
||||||
if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) {
|
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.ambient_texname = token;
|
material.ambient_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// diffuse texture
|
// diffuse texture
|
||||||
if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) {
|
if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.diffuse_texname = token;
|
material.diffuse_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// specular texture
|
// specular texture
|
||||||
if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) {
|
if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.specular_texname = token;
|
material.specular_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// specular highlight texture
|
// specular highlight texture
|
||||||
if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) {
|
if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.specular_highlight_texname = token;
|
material.specular_highlight_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bump texture
|
// bump texture
|
||||||
if ((0 == strncmp(token, "map_bump", 8)) && isSpace(token[8])) {
|
if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) {
|
||||||
token += 9;
|
token += 9;
|
||||||
material.bump_texname = token;
|
material.bump_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// alpha texture
|
// alpha texture
|
||||||
if ((0 == strncmp(token, "map_d", 5)) && isSpace(token[5])) {
|
if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) {
|
||||||
token += 6;
|
token += 6;
|
||||||
material.alpha_texname = token;
|
material.alpha_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bump texture
|
// bump texture
|
||||||
if ((0 == strncmp(token, "bump", 4)) && isSpace(token[4])) {
|
if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
|
||||||
token += 5;
|
token += 5;
|
||||||
material.bump_texname = token;
|
material.bump_texname = token;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// displacement texture
|
// displacement texture
|
||||||
if ((0 == strncmp(token, "disp", 4)) && isSpace(token[4])) {
|
if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
|
||||||
token += 5;
|
token += 5;
|
||||||
material.displacement_texname = token;
|
material.displacement_texname = token;
|
||||||
continue;
|
continue;
|
||||||
@@ -914,7 +913,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
continue; // comment line
|
continue; // comment line
|
||||||
|
|
||||||
// vertex
|
// vertex
|
||||||
if (token[0] == 'v' && isSpace((token[1]))) {
|
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
parseFloat3(x, y, z, token);
|
parseFloat3(x, y, z, token);
|
||||||
@@ -925,7 +924,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// normal
|
// normal
|
||||||
if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) {
|
if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
|
||||||
token += 3;
|
token += 3;
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
parseFloat3(x, y, z, token);
|
parseFloat3(x, y, z, token);
|
||||||
@@ -936,7 +935,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// texcoord
|
// texcoord
|
||||||
if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) {
|
if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||||
token += 3;
|
token += 3;
|
||||||
float x, y;
|
float x, y;
|
||||||
parseFloat2(x, y, token);
|
parseFloat2(x, y, token);
|
||||||
@@ -946,12 +945,14 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// face
|
// face
|
||||||
if (token[0] == 'f' && isSpace((token[1]))) {
|
if (token[0] == 'f' && IS_SPACE((token[1]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
token += strspn(token, " \t");
|
token += strspn(token, " \t");
|
||||||
|
|
||||||
std::vector<vertex_index> face;
|
std::vector<vertex_index> face;
|
||||||
while (!isNewLine(token[0])) {
|
face.reserve(3);
|
||||||
|
|
||||||
|
while (!IS_NEW_LINE(token[0])) {
|
||||||
vertex_index vi = parseTriple(token, static_cast<int>(v.size() / 3),
|
vertex_index vi = parseTriple(token, static_cast<int>(v.size() / 3),
|
||||||
static_cast<int>(vn.size() / 3),
|
static_cast<int>(vn.size() / 3),
|
||||||
static_cast<int>(vt.size() / 2));
|
static_cast<int>(vt.size() / 2));
|
||||||
@@ -960,13 +961,15 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
token += n;
|
token += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
faceGroup.push_back(face);
|
// replace with emplace_back + std::move on C++11
|
||||||
|
faceGroup.push_back(std::vector<vertex_index>());
|
||||||
|
faceGroup[faceGroup.size() - 1].swap(face);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use mtl
|
// use mtl
|
||||||
if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) {
|
if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) {
|
||||||
|
|
||||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||||
token += 7;
|
token += 7;
|
||||||
@@ -976,28 +979,26 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
sscanf(token, "%s", namebuf);
|
sscanf(token, "%s", namebuf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create face group per material.
|
int newMaterialId = -1;
|
||||||
bool ret =
|
|
||||||
exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags,
|
|
||||||
material, name, true, triangulate);
|
|
||||||
if (ret) {
|
|
||||||
shapes.push_back(shape);
|
|
||||||
}
|
|
||||||
shape = shape_t();
|
|
||||||
faceGroup.clear();
|
|
||||||
|
|
||||||
if (material_map.find(namebuf) != material_map.end()) {
|
if (material_map.find(namebuf) != material_map.end()) {
|
||||||
material = material_map[namebuf];
|
newMaterialId = material_map[namebuf];
|
||||||
} else {
|
} else {
|
||||||
// { error!! material not found }
|
// { error!! material not found }
|
||||||
material = -1;
|
}
|
||||||
|
|
||||||
|
if (newMaterialId != material) {
|
||||||
|
// Create per-face material
|
||||||
|
exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags,
|
||||||
|
material, name, true, triangulate);
|
||||||
|
faceGroup.clear();
|
||||||
|
material = newMaterialId;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load mtl
|
// load mtl
|
||||||
if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) {
|
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
||||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||||
token += 7;
|
token += 7;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -1019,7 +1020,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// group name
|
// group name
|
||||||
if (token[0] == 'g' && isSpace((token[1]))) {
|
if (token[0] == 'g' && IS_SPACE((token[1]))) {
|
||||||
|
|
||||||
// flush previous face group.
|
// flush previous face group.
|
||||||
bool ret =
|
bool ret =
|
||||||
@@ -1035,7 +1036,9 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
faceGroup.clear();
|
faceGroup.clear();
|
||||||
|
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
while (!isNewLine(token[0])) {
|
names.reserve(2);
|
||||||
|
|
||||||
|
while (!IS_NEW_LINE(token[0])) {
|
||||||
std::string str = parseString(token);
|
std::string str = parseString(token);
|
||||||
names.push_back(str);
|
names.push_back(str);
|
||||||
token += strspn(token, " \t\r"); // skip tag
|
token += strspn(token, " \t\r"); // skip tag
|
||||||
@@ -1054,7 +1057,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// object name
|
// object name
|
||||||
if (token[0] == 'o' && isSpace((token[1]))) {
|
if (token[0] == 'o' && IS_SPACE((token[1]))) {
|
||||||
|
|
||||||
// flush previous face group.
|
// flush previous face group.
|
||||||
bool ret =
|
bool ret =
|
||||||
@@ -1081,7 +1084,7 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token[0] == 't' && isSpace(token[1])) {
|
if (token[0] == 't' && IS_SPACE(token[1])) {
|
||||||
tag_t tag;
|
tag_t tag;
|
||||||
|
|
||||||
char namebuf[4096];
|
char namebuf[4096];
|
||||||
|
|||||||
Reference in New Issue
Block a user