Compare commits
2 Commits
afl
...
better-cxx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e2cd27c64 | ||
|
|
49726abcf1 |
@@ -98,7 +98,6 @@ TinyObjLoader is successfully used in ...
|
|||||||
* PBR material extension for .MTL. Its proposed here: http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
* PBR material extension for .MTL. Its proposed here: http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
||||||
* Callback API for custom loading.
|
* Callback API for custom loading.
|
||||||
* Double precision support(for HPC application).
|
* Double precision support(for HPC application).
|
||||||
* Smoothing group
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
@@ -106,6 +105,8 @@ TinyObjLoader is successfully used in ...
|
|||||||
* [ ] Fix obj_sticker example.
|
* [ ] Fix obj_sticker example.
|
||||||
* [ ] More unit test codes.
|
* [ ] More unit test codes.
|
||||||
* [x] Texture options
|
* [x] Texture options
|
||||||
|
* [ ] Normal vector generation
|
||||||
|
* [ ] Support smoothing groups
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -172,3 +172,5 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ extern "C" {
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#ifdef max
|
#ifdef max
|
||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
@@ -143,15 +143,15 @@ float eye[3], lookat[3], up[3];
|
|||||||
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
|
||||||
static std::string GetBaseDir(const std::string& filepath) {
|
static std::string GetBaseDir(const std::string &filepath) {
|
||||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FileExists(const std::string& abs_filename) {
|
static bool FileExists(const std::string &abs_filename) {
|
||||||
bool ret;
|
bool ret;
|
||||||
FILE* fp = fopen(abs_filename.c_str(), "rb");
|
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
ret = true;
|
ret = true;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -191,106 +191,14 @@ static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
|||||||
|
|
||||||
N[0] /= len;
|
N[0] /= len;
|
||||||
N[1] /= len;
|
N[1] /= len;
|
||||||
N[2] /= len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace // Local utility functions
|
|
||||||
{
|
|
||||||
struct vec3 {
|
|
||||||
float v[3];
|
|
||||||
vec3() {
|
|
||||||
v[0] = 0.0f;
|
|
||||||
v[1] = 0.0f;
|
|
||||||
v[2] = 0.0f;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void normalizeVector(vec3 &v) {
|
|
||||||
float len2 = v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2];
|
|
||||||
if (len2 > 0.0f) {
|
|
||||||
float len = sqrtf(len2);
|
|
||||||
|
|
||||||
v.v[0] /= len;
|
|
||||||
v.v[1] /= len;
|
|
||||||
v.v[2] /= len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if `mesh_t` contains smoothing group id.
|
|
||||||
bool hasSmoothingGroup(const tinyobj::shape_t& shape)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < shape.mesh.smoothing_group_ids.size(); i++) {
|
|
||||||
if (shape.mesh.smoothing_group_ids[i] > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void computeSmoothingNormals(const tinyobj::attrib_t& attrib, const tinyobj::shape_t& shape,
|
|
||||||
std::map<int, vec3>& smoothVertexNormals) {
|
|
||||||
smoothVertexNormals.clear();
|
|
||||||
std::map<int, vec3>::iterator iter;
|
|
||||||
|
|
||||||
for (size_t f = 0; f < shape.mesh.indices.size() / 3; f++) {
|
|
||||||
// Get the three indexes of the face (all faces are triangular)
|
|
||||||
tinyobj::index_t idx0 = shape.mesh.indices[3 * f + 0];
|
|
||||||
tinyobj::index_t idx1 = shape.mesh.indices[3 * f + 1];
|
|
||||||
tinyobj::index_t idx2 = shape.mesh.indices[3 * f + 2];
|
|
||||||
|
|
||||||
// Get the three vertex indexes and coordinates
|
|
||||||
int vi[3]; // indexes
|
|
||||||
float v[3][3]; // coordinates
|
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
vi[0] = idx0.vertex_index;
|
|
||||||
vi[1] = idx1.vertex_index;
|
|
||||||
vi[2] = idx2.vertex_index;
|
|
||||||
assert(vi[0] >= 0);
|
|
||||||
assert(vi[1] >= 0);
|
|
||||||
assert(vi[2] >= 0);
|
|
||||||
|
|
||||||
v[0][k] = attrib.vertices[3 * vi[0] + k];
|
|
||||||
v[1][k] = attrib.vertices[3 * vi[1] + k];
|
|
||||||
v[2][k] = attrib.vertices[3 * vi[2] + k];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the normal of the face
|
|
||||||
float normal[3];
|
|
||||||
CalcNormal(normal, v[0], v[1], v[2]);
|
|
||||||
|
|
||||||
// Add the normal to the three vertexes
|
|
||||||
for (size_t i = 0; i < 3; ++i) {
|
|
||||||
iter = smoothVertexNormals.find(vi[i]);
|
|
||||||
if (iter != smoothVertexNormals.end()) {
|
|
||||||
// add
|
|
||||||
iter->second.v[0] += normal[0];
|
|
||||||
iter->second.v[1] += normal[1];
|
|
||||||
iter->second.v[2] += normal[2];
|
|
||||||
} else {
|
|
||||||
smoothVertexNormals[vi[i]].v[0] = normal[0];
|
|
||||||
smoothVertexNormals[vi[i]].v[1] = normal[1];
|
|
||||||
smoothVertexNormals[vi[i]].v[2] = normal[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // f
|
|
||||||
|
|
||||||
// Normalize the normals, that is, make them unit vectors
|
|
||||||
for (iter = smoothVertexNormals.begin(); iter != smoothVertexNormals.end();
|
|
||||||
iter++) {
|
|
||||||
normalizeVector(iter->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // computeSmoothingNormals
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
||||||
std::vector<DrawObject>* drawObjects,
|
std::vector<DrawObject>* drawObjects,
|
||||||
std::vector<tinyobj::material_t>& materials,
|
std::vector<tinyobj::material_t>& materials,
|
||||||
std::map<std::string, GLuint>& textures,
|
std::map<std::string, GLuint>& textures,
|
||||||
const char* filename) {
|
const char* filename) {
|
||||||
tinyobj::attrib_t attrib;
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
|
||||||
@@ -309,8 +217,8 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
|
bool ret =
|
||||||
base_dir.c_str());
|
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, base_dir.c_str());
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
}
|
}
|
||||||
@@ -334,62 +242,56 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
materials.push_back(tinyobj::material_t());
|
materials.push_back(tinyobj::material_t());
|
||||||
|
|
||||||
for (size_t i = 0; i < materials.size(); i++) {
|
for (size_t i = 0; i < materials.size(); i++) {
|
||||||
printf("material[%d].diffuse_texname = %s\n", int(i),
|
printf("material[%d].diffuse_texname = %s\n", int(i), materials[i].diffuse_texname.c_str());
|
||||||
materials[i].diffuse_texname.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load diffuse textures
|
// Load diffuse textures
|
||||||
{
|
{
|
||||||
for (size_t m = 0; m < materials.size(); m++) {
|
for (size_t m = 0; m < materials.size(); m++) {
|
||||||
tinyobj::material_t* mp = &materials[m];
|
tinyobj::material_t* mp = &materials[m];
|
||||||
|
|
||||||
|
if (mp->diffuse_texname.length() > 0) {
|
||||||
|
// Only load the texture if it is not already loaded
|
||||||
|
if (textures.find(mp->diffuse_texname) == textures.end()) {
|
||||||
|
GLuint texture_id;
|
||||||
|
int w, h;
|
||||||
|
int comp;
|
||||||
|
|
||||||
if (mp->diffuse_texname.length() > 0) {
|
std::string texture_filename = mp->diffuse_texname;
|
||||||
// Only load the texture if it is not already loaded
|
if (!FileExists(texture_filename)) {
|
||||||
if (textures.find(mp->diffuse_texname) == textures.end()) {
|
// Append base dir.
|
||||||
GLuint texture_id;
|
texture_filename = base_dir + mp->diffuse_texname;
|
||||||
int w, h;
|
if (!FileExists(texture_filename)) {
|
||||||
int comp;
|
std::cerr << "Unable to find file: " << mp->diffuse_texname << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* image = stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
|
||||||
|
if (!image) {
|
||||||
|
std::cerr << "Unable to load texture: " << texture_filename << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::cout << "Loaded texture: " << texture_filename << ", w = " << w << ", h = " << h << ", comp = " << comp << std::endl;
|
||||||
|
|
||||||
std::string texture_filename = mp->diffuse_texname;
|
glGenTextures(1, &texture_id);
|
||||||
if (!FileExists(texture_filename)) {
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
||||||
// Append base dir.
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
texture_filename = base_dir + mp->diffuse_texname;
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
if (!FileExists(texture_filename)) {
|
if (comp == 3) {
|
||||||
std::cerr << "Unable to find file: " << mp->diffuse_texname
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||||
<< std::endl;
|
}
|
||||||
exit(1);
|
else if (comp == 4) {
|
||||||
}
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||||
|
} else {
|
||||||
|
assert(0); // TODO
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
stbi_image_free(image);
|
||||||
|
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* image =
|
|
||||||
stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
|
|
||||||
if (!image) {
|
|
||||||
std::cerr << "Unable to load texture: " << texture_filename
|
|
||||||
<< std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
std::cout << "Loaded texture: " << texture_filename << ", w = " << w
|
|
||||||
<< ", h = " << h << ", comp = " << comp << std::endl;
|
|
||||||
|
|
||||||
glGenTextures(1, &texture_id);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
if (comp == 3) {
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
|
|
||||||
GL_UNSIGNED_BYTE, image);
|
|
||||||
} else if (comp == 4) {
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE, image);
|
|
||||||
} else {
|
|
||||||
assert(0); // TODO
|
|
||||||
}
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
stbi_image_free(image);
|
|
||||||
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||||
@@ -399,55 +301,30 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
for (size_t s = 0; s < shapes.size(); s++) {
|
for (size_t s = 0; s < shapes.size(); s++) {
|
||||||
DrawObject o;
|
DrawObject o;
|
||||||
std::vector<float> buffer; // pos(3float), normal(3float), color(3float)
|
std::vector<float> buffer; // pos(3float), normal(3float), color(3float)
|
||||||
|
|
||||||
// Check for smoothing group and compute smoothing normals
|
|
||||||
std::map<int, vec3> smoothVertexNormals;
|
|
||||||
if (hasSmoothingGroup(shapes[s]) > 0) {
|
|
||||||
std::cout << "Compute smoothingNormal for shape [" << s << "]" << std::endl;
|
|
||||||
computeSmoothingNormals(attrib, shapes[s], smoothVertexNormals);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
|
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
|
||||||
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
|
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
|
||||||
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
|
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
|
||||||
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
|
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
|
||||||
|
|
||||||
int current_material_id = shapes[s].mesh.material_ids[f];
|
int current_material_id = shapes[s].mesh.material_ids[f];
|
||||||
|
|
||||||
if ((current_material_id < 0) ||
|
if ((current_material_id < 0) || (current_material_id >= static_cast<int>(materials.size()))) {
|
||||||
(current_material_id >= static_cast<int>(materials.size()))) {
|
|
||||||
// Invaid material ID. Use default material.
|
// Invaid material ID. Use default material.
|
||||||
current_material_id =
|
current_material_id = materials.size() - 1; // Default material is added to the last item in `materials`.
|
||||||
materials.size() -
|
|
||||||
1; // Default material is added to the last item in `materials`.
|
|
||||||
}
|
}
|
||||||
// if (current_material_id >= materials.size()) {
|
//if (current_material_id >= materials.size()) {
|
||||||
// std::cerr << "Invalid material index: " << current_material_id <<
|
// std::cerr << "Invalid material index: " << current_material_id << std::endl;
|
||||||
// std::endl;
|
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
float diffuse[3];
|
float diffuse[3];
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
diffuse[i] = materials[current_material_id].diffuse[i];
|
diffuse[i] = materials[current_material_id].diffuse[i];
|
||||||
}
|
}
|
||||||
float tc[3][2];
|
float tc[3][2];
|
||||||
if (attrib.texcoords.size() > 0) {
|
if (attrib.texcoords.size() > 0) {
|
||||||
if ((idx0.texcoord_index < 0) || (idx1.texcoord_index < 0) ||
|
assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1);
|
||||||
(idx2.texcoord_index < 0)) {
|
assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1);
|
||||||
// face does not contain valid uv index.
|
assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1);
|
||||||
tc[0][0] = 0.0f;
|
|
||||||
tc[0][1] = 0.0f;
|
|
||||||
tc[1][0] = 0.0f;
|
|
||||||
tc[1][1] = 0.0f;
|
|
||||||
tc[2][0] = 0.0f;
|
|
||||||
tc[2][1] = 0.0f;
|
|
||||||
} else {
|
|
||||||
assert(attrib.texcoords.size() >
|
|
||||||
size_t(2 * idx0.texcoord_index + 1));
|
|
||||||
assert(attrib.texcoords.size() >
|
|
||||||
size_t(2 * idx1.texcoord_index + 1));
|
|
||||||
assert(attrib.texcoords.size() >
|
|
||||||
size_t(2 * idx2.texcoord_index + 1));
|
|
||||||
|
|
||||||
// Flip Y coord.
|
// Flip Y coord.
|
||||||
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
|
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
|
||||||
@@ -456,14 +333,13 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
|
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
|
||||||
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
|
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
|
||||||
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
|
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tc[0][0] = 0.0f;
|
tc[0][0] = 0.0f;
|
||||||
tc[0][1] = 0.0f;
|
tc[0][1] = 0.0f;
|
||||||
tc[1][0] = 0.0f;
|
tc[1][0] = 0.0f;
|
||||||
tc[1][1] = 0.0f;
|
tc[1][1] = 0.0f;
|
||||||
tc[2][0] = 0.0f;
|
tc[2][0] = 0.0f;
|
||||||
tc[2][1] = 0.0f;
|
tc[2][1] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float v[3][3];
|
float v[3][3];
|
||||||
@@ -487,63 +363,27 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
}
|
}
|
||||||
|
|
||||||
float n[3][3];
|
float n[3][3];
|
||||||
{
|
if (attrib.normals.size() > 0) {
|
||||||
bool invalid_normal_index = false;
|
int f0 = idx0.normal_index;
|
||||||
if (attrib.normals.size() > 0) {
|
int f1 = idx1.normal_index;
|
||||||
int nf0 = idx0.normal_index;
|
int f2 = idx2.normal_index;
|
||||||
int nf1 = idx1.normal_index;
|
assert(f0 >= 0);
|
||||||
int nf2 = idx2.normal_index;
|
assert(f1 >= 0);
|
||||||
|
assert(f2 >= 0);
|
||||||
if ((nf0 < 0) || (nf1 < 0) || (nf2 < 0)) {
|
for (int k = 0; k < 3; k++) {
|
||||||
// normal index is missing from this face.
|
n[0][k] = attrib.normals[3 * f0 + k];
|
||||||
invalid_normal_index = true;
|
n[1][k] = attrib.normals[3 * f1 + k];
|
||||||
} else {
|
n[2][k] = attrib.normals[3 * f2 + k];
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
assert(size_t(3 * nf0 + k) < attrib.normals.size());
|
|
||||||
assert(size_t(3 * nf1 + k) < attrib.normals.size());
|
|
||||||
assert(size_t(3 * nf2 + k) < attrib.normals.size());
|
|
||||||
n[0][k] = attrib.normals[3 * nf0 + k];
|
|
||||||
n[1][k] = attrib.normals[3 * nf1 + k];
|
|
||||||
n[2][k] = attrib.normals[3 * nf2 + k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
invalid_normal_index = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invalid_normal_index && !smoothVertexNormals.empty()) {
|
|
||||||
// Use smoothing normals
|
|
||||||
int f0 = idx0.vertex_index;
|
|
||||||
int f1 = idx1.vertex_index;
|
|
||||||
int f2 = idx2.vertex_index;
|
|
||||||
|
|
||||||
if (f0 >= 0 && f1 >= 0 && f2 >= 0) {
|
|
||||||
n[0][0] = smoothVertexNormals[f0].v[0];
|
|
||||||
n[0][1] = smoothVertexNormals[f0].v[1];
|
|
||||||
n[0][2] = smoothVertexNormals[f0].v[2];
|
|
||||||
|
|
||||||
n[1][0] = smoothVertexNormals[f1].v[0];
|
|
||||||
n[1][1] = smoothVertexNormals[f1].v[1];
|
|
||||||
n[1][2] = smoothVertexNormals[f1].v[2];
|
|
||||||
|
|
||||||
n[2][0] = smoothVertexNormals[f2].v[0];
|
|
||||||
n[2][1] = smoothVertexNormals[f2].v[1];
|
|
||||||
n[2][2] = smoothVertexNormals[f2].v[2];
|
|
||||||
|
|
||||||
invalid_normal_index = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invalid_normal_index) {
|
|
||||||
// compute geometric normal
|
|
||||||
CalcNormal(n[0], v[0], v[1], v[2]);
|
|
||||||
n[1][0] = n[0][0];
|
|
||||||
n[1][1] = n[0][1];
|
|
||||||
n[1][2] = n[0][2];
|
|
||||||
n[2][0] = n[0][0];
|
|
||||||
n[2][1] = n[0][1];
|
|
||||||
n[2][2] = n[0][2];
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// compute geometric normal
|
||||||
|
CalcNormal(n[0], v[0], v[1], v[2]);
|
||||||
|
n[1][0] = n[0][0];
|
||||||
|
n[1][1] = n[0][1];
|
||||||
|
n[1][2] = n[0][2];
|
||||||
|
n[2][0] = n[0][0];
|
||||||
|
n[2][1] = n[0][1];
|
||||||
|
n[2][2] = n[0][2];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
@@ -556,9 +396,11 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
// Combine normal and diffuse to get color.
|
// Combine normal and diffuse to get color.
|
||||||
float normal_factor = 0.2;
|
float normal_factor = 0.2;
|
||||||
float diffuse_factor = 1 - normal_factor;
|
float diffuse_factor = 1 - normal_factor;
|
||||||
float c[3] = {n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
|
float c[3] = {
|
||||||
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
|
n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
|
||||||
n[k][2] * normal_factor + diffuse[2] * diffuse_factor};
|
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
|
||||||
|
n[k][2] * normal_factor + diffuse[2] * diffuse_factor
|
||||||
|
};
|
||||||
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
|
||||||
if (len2 > 0.0f) {
|
if (len2 > 0.0f) {
|
||||||
float len = sqrtf(len2);
|
float len = sqrtf(len2);
|
||||||
@@ -570,7 +412,7 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
buffer.push_back(c[0] * 0.5 + 0.5);
|
buffer.push_back(c[0] * 0.5 + 0.5);
|
||||||
buffer.push_back(c[1] * 0.5 + 0.5);
|
buffer.push_back(c[1] * 0.5 + 0.5);
|
||||||
buffer.push_back(c[2] * 0.5 + 0.5);
|
buffer.push_back(c[2] * 0.5 + 0.5);
|
||||||
|
|
||||||
buffer.push_back(tc[k][0]);
|
buffer.push_back(tc[k][0]);
|
||||||
buffer.push_back(tc[k][1]);
|
buffer.push_back(tc[k][1]);
|
||||||
}
|
}
|
||||||
@@ -580,22 +422,19 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
o.numTriangles = 0;
|
o.numTriangles = 0;
|
||||||
|
|
||||||
// OpenGL viewer does not support texturing with per-face material.
|
// OpenGL viewer does not support texturing with per-face material.
|
||||||
if (shapes[s].mesh.material_ids.size() > 0 &&
|
if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
|
||||||
shapes[s].mesh.material_ids.size() > s) {
|
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID of the first face.
|
||||||
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID
|
|
||||||
// of the first face.
|
|
||||||
} else {
|
} else {
|
||||||
o.material_id = materials.size() - 1; // = ID for default material.
|
o.material_id = materials.size() - 1; // = ID for default material.
|
||||||
}
|
}
|
||||||
printf("shape[%d] material_id %d\n", int(s), int(o.material_id));
|
printf("shape[%d] material_id %d\n", int(s), int(o.material_id));
|
||||||
|
|
||||||
if (buffer.size() > 0) {
|
if (buffer.size() > 0) {
|
||||||
glGenBuffers(1, &o.vb_id);
|
glGenBuffers(1, &o.vb_id);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
|
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
|
||||||
glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float),
|
glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float), &buffer.at(0),
|
||||||
&buffer.at(0), GL_STATIC_DRAW);
|
GL_STATIC_DRAW);
|
||||||
o.numTriangles = buffer.size() / (3 + 3 + 3 + 2) /
|
o.numTriangles = buffer.size() / (3 + 3 + 3 + 2) / 3; // 3:vtx, 3:normal, 3:col, 2:texcoord
|
||||||
3; // 3:vtx, 3:normal, 3:col, 2:texcoord
|
|
||||||
|
|
||||||
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
|
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
|
||||||
o.numTriangles);
|
o.numTriangles);
|
||||||
@@ -628,7 +467,7 @@ static void reshapeFunc(GLFWwindow* window, int w, int h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
|
static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
|
||||||
int mods) {
|
int mods) {
|
||||||
(void)window;
|
(void)window;
|
||||||
(void)scancode;
|
(void)scancode;
|
||||||
(void)mods;
|
(void)mods;
|
||||||
@@ -710,9 +549,7 @@ static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
|||||||
prevMouseY = mouse_y;
|
prevMouseY = mouse_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Draw(const std::vector<DrawObject>& drawObjects,
|
static void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t>& materials, std::map<std::string, GLuint>& textures) {
|
||||||
std::vector<tinyobj::material_t>& materials,
|
|
||||||
std::map<std::string, GLuint>& textures) {
|
|
||||||
glPolygonMode(GL_FRONT, GL_FILL);
|
glPolygonMode(GL_FRONT, GL_FILL);
|
||||||
glPolygonMode(GL_BACK, GL_FILL);
|
glPolygonMode(GL_BACK, GL_FILL);
|
||||||
|
|
||||||
@@ -735,7 +572,7 @@ static void Draw(const std::vector<DrawObject>& drawObjects,
|
|||||||
if ((o.material_id < materials.size())) {
|
if ((o.material_id < materials.size())) {
|
||||||
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
||||||
if (textures.find(diffuse_texname) != textures.end()) {
|
if (textures.find(diffuse_texname) != textures.end()) {
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
@@ -831,8 +668,7 @@ int main(int argc, char** argv) {
|
|||||||
float bmin[3], bmax[3];
|
float bmin[3], bmax[3];
|
||||||
std::vector<tinyobj::material_t> materials;
|
std::vector<tinyobj::material_t> materials;
|
||||||
std::map<std::string, GLuint> textures;
|
std::map<std::string, GLuint> textures;
|
||||||
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures,
|
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) {
|
||||||
argv[1])) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import os, sys
|
|
||||||
import glob
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
def main():
|
|
||||||
for g in glob.glob("../tests/afl/id*"):
|
|
||||||
print(g)
|
|
||||||
|
|
||||||
cmd = ["../a.out", g]
|
|
||||||
|
|
||||||
proc = subprocess.Popen(cmd)
|
|
||||||
try:
|
|
||||||
outs, errs = proc.communicate(timeout=15)
|
|
||||||
print(outs)
|
|
||||||
except TimeoutExpired:
|
|
||||||
proc.kill()
|
|
||||||
outs, errs = proc.communicate()
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
@@ -29,10 +29,10 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TINYOBJ_USE_CXX11
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -70,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,9 +145,6 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
|
|||||||
assert(shapes[i].mesh.num_face_vertices.size() ==
|
assert(shapes[i].mesh.num_face_vertices.size() ==
|
||||||
shapes[i].mesh.material_ids.size());
|
shapes[i].mesh.material_ids.size());
|
||||||
|
|
||||||
assert(shapes[i].mesh.num_face_vertices.size() ==
|
|
||||||
shapes[i].mesh.smoothing_group_ids.size());
|
|
||||||
|
|
||||||
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
|
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
|
||||||
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
|
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
|
||||||
|
|
||||||
@@ -168,8 +165,6 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
|
|||||||
|
|
||||||
printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
|
printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
|
||||||
shapes[i].mesh.material_ids[f]);
|
shapes[i].mesh.material_ids[f]);
|
||||||
printf(" face[%ld].smoothing_group_id = %d\n", static_cast<long>(f),
|
|
||||||
shapes[i].mesh.smoothing_group_ids[f]);
|
|
||||||
|
|
||||||
index_offset += fnum;
|
index_offset += fnum;
|
||||||
}
|
}
|
||||||
@@ -273,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;
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
o cube
|
|
||||||
mtllib cube.mtl
|
|
||||||
|
|
||||||
v -0.500000 -0.500000 0.500000
|
|
||||||
v 0.500000 -0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 0.500000
|
|
||||||
v 0.500000 0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 -0.500000
|
|
||||||
v 0.500000 0.500000 -0.500000
|
|
||||||
v -0.500000 -0.500000 -0.500000
|
|
||||||
v 0.500000 -0.500000 -0.500000
|
|
||||||
|
|
||||||
vt 0.000000 0.000000
|
|
||||||
vt 1.000000 0.000000
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
|
|
||||||
g cube
|
|
||||||
usemtl cube
|
|
||||||
s 1
|
|
||||||
f 1/1 2/2 3/3
|
|
||||||
f 3/3 2/2 4/4
|
|
||||||
s 2
|
|
||||||
f 3/1 4/2 5/3
|
|
||||||
f 5/3 4/2 6/4
|
|
||||||
s 3
|
|
||||||
f 5/4 6/3 7/2
|
|
||||||
f 7/2 6/3 8/1
|
|
||||||
s 4
|
|
||||||
f 7/1 8/2 1/3
|
|
||||||
f 1/3 8/2 2/4
|
|
||||||
s 5
|
|
||||||
f 2/1 8/2 4/3
|
|
||||||
f 4/3 8/2 6/4
|
|
||||||
s 6
|
|
||||||
f 7/1 1/2 5/3
|
|
||||||
f 5 1 3
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
newmtl test1
|
|
||||||
Ns 10.0000
|
|
||||||
Ni 1.5000
|
|
||||||
d 1.0000
|
|
||||||
Tr 0.0000
|
|
||||||
Tf 1.0000 1.0000 1.0000
|
|
||||||
illum 2
|
|
||||||
Ka 0.0000 0.0000 0.0000
|
|
||||||
Kd 0.5 0.2 0.2
|
|
||||||
Ks 0.0000 0.0000 0.0000
|
|
||||||
Ke 0.0000 0.0000 0.0000
|
|
||||||
|
|
||||||
newmtl test2
|
|
||||||
Ns 10.0000
|
|
||||||
Ni 1.5000
|
|
||||||
d 1.0000
|
|
||||||
Tr 0.0000
|
|
||||||
Tf 1.0000 1.0000 1.0000
|
|
||||||
illum 2
|
|
||||||
Ka 0.0000 0.0000 0.0000
|
|
||||||
Kd 0.2 0.5 0.2
|
|
||||||
Ks 0.0000 0.0000 0.0000
|
|
||||||
Ke 0.0000 0.0000 0.0000
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
|
|
||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
mtllib issue-162-smoothing-group.mtl
|
|
||||||
|
|
||||||
v -0.500000 -0.500000 0.500000
|
|
||||||
v 0.500000 -0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 0.500000
|
|
||||||
v 0.500000 0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 -0.500000
|
|
||||||
v 0.500000 0.500000 -0.500000
|
|
||||||
v -0.500000 -0.500000 -0.500000
|
|
||||||
v 0.500000 -0.500000 -0.500000
|
|
||||||
|
|
||||||
vt 0.000000 0.000000
|
|
||||||
vt 1.000000 0.000000
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
|
|
||||||
vn 0.000000 0.000000 1.000000
|
|
||||||
vn 0.000000 1.000000 0.000000
|
|
||||||
vn 0.000000 0.000000 -1.000000
|
|
||||||
vn 0.000000 -1.000000 0.000000
|
|
||||||
vn 1.000000 0.000000 0.000000
|
|
||||||
vn -1.000000 0.000000 0.000000
|
|
||||||
|
|
||||||
usemtl test1
|
|
||||||
g test1
|
|
||||||
s 1
|
|
||||||
f 1/1/1 2/2/1 3/3/1
|
|
||||||
f 3/3/1 2/2/1 4/4/1
|
|
||||||
|
|
||||||
usemtl test2
|
|
||||||
g test2
|
|
||||||
|
|
||||||
s off
|
|
||||||
f 3/1/2 4/2/2 5/3/2
|
|
||||||
f 5/3/2 4/2/2 6/4/2
|
|
||||||
s 3
|
|
||||||
f 5/4/3 6/3/3 7/2/3
|
|
||||||
f 7/2/3 6/3/3 8/1/3
|
|
||||||
s 4
|
|
||||||
f 7/1/4 8/2/4 1/3/4
|
|
||||||
f 1/3/4 8/2/4 2/4/4
|
|
||||||
s 0
|
|
||||||
f 2/1/5 8/2/5 4/3/5
|
|
||||||
f 4/3/5 8/2/5 6/4/5
|
|
||||||
s 6
|
|
||||||
f 7/1/6 1/2/6 5/3/6
|
|
||||||
f 5/3/6 1/2/6 3/4/6
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# from tinyobjloader issue #29
|
|
||||||
|
|
||||||
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
|
|
||||||
v 4.000000 0.000000 -3.255298
|
|
||||||
v 4.000000 2.000000 -3.255298
|
|
||||||
#vn 0.000000 0.000000 1.000000
|
|
||||||
#vn 0.000000 0.000000 1.000000
|
|
||||||
#vn 0.276597 0.000000 0.960986
|
|
||||||
#vn 0.276597 0.000000 0.960986
|
|
||||||
#vn 0.531611 0.000000 0.846988
|
|
||||||
#vn 0.531611 0.000000 0.846988
|
|
||||||
# 6 vertices
|
|
||||||
|
|
||||||
# 6 normals
|
|
||||||
|
|
||||||
g all
|
|
||||||
s 1
|
|
||||||
f 1//1 2//2 3//3 4//4
|
|
||||||
f 4//4 3//3 5//5
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
newmtl white
|
|
||||||
Ka 0 0 0
|
|
||||||
Kd 1 1 1
|
|
||||||
Ks 0 0 0
|
|
||||||
|
|
||||||
newmtl red
|
|
||||||
Ka 0 0 0
|
|
||||||
Kd 1 0 0
|
|
||||||
Ks 0 0 0
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
mtllib smoothing-normal.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
|
|
||||||
s 1
|
|
||||||
f 1 2 3 4
|
|
||||||
#g bottom cube
|
|
||||||
#usemtl white
|
|
||||||
s 1
|
|
||||||
f 2 6 7 3
|
|
||||||
|
|
||||||
g back cube
|
|
||||||
# expects white material
|
|
||||||
s off
|
|
||||||
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
|
|
||||||
# 6 elements
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
Command line used to find this crash:
|
|
||||||
|
|
||||||
afl-fuzz -i in -o out ./test_loader @@
|
|
||||||
|
|
||||||
If you can't reproduce a bug outside of afl-fuzz, be sure to set the same
|
|
||||||
memory limit. The limit used for this fuzzing session was 50.0 MB.
|
|
||||||
|
|
||||||
Need a tool to minimize test cases before investigating the crashes or sending
|
|
||||||
them to a vendor? Check out the afl-tmin that comes with the fuzzer!
|
|
||||||
|
|
||||||
Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop
|
|
||||||
me a mail at <lcamtuf@coredump.cx> once the issues are fixed - I'd love to
|
|
||||||
add your finds to the gallery at:
|
|
||||||
|
|
||||||
http://lcamtuf.coredump.cx/afl/
|
|
||||||
|
|
||||||
Thanks :-)
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,33 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
} cube
|
|
||||||
|
|
||||||
v d.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1/6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 55555555555555 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
n 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 //5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# cube.ob7//3
|
|
||||||
f 3//3 4//3 8//3j
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1˙0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,29 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1,0
|
|
||||||
T 0.0 1.0 0.0
|
|
||||||
v 4.0 1c0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 /////////////////////////////.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
v˙ 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8K/31
|
|
||||||
f/6 4//6 3//6
|
|
||||||
f 1//6 2 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5"
|
|
||||||
f 1//4 5//4 2222222222224f 1//2 7//2 5 6//4 2//4
|
|
||||||
f 3//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0<>0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 00
|
|
||||||
vn 0.0 -Ę.0 0.0
|
|
||||||
vn 1. 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 40000000000000000vvvvvvvvvvvvvvvv00000080000000//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
f 1//4 56//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
@@ -1,32 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 08//3
|
|
||||||
f 5//5 7//5 8//5!Šf 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 65555//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
@@ -1,33 +0,0 @@
|
|||||||
# cube.7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v .0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5!Šf 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cuvP 0.0 0.0 .0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5!Šf 5//5 8//5 6//5
|
|
||||||
f 1//4 5//4 6//4
|
|
||||||
f 1//4 6666666666666666//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
t 1//4 5/-4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
t 1//4 -5//4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
@@ -1,35 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v 1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 !.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0 0.0
|
|
||||||
vn 0.0 8//5 6//5
|
|
||||||
t 1//4 -1.0 0.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 8//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
t 1//4 5//4 6//4
|
|
||||||
f 1//4 6//4 2//4 f 2//1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,32 +0,0 @@
|
|||||||
# cube.obj
|
|
||||||
#
|
|
||||||
|
|
||||||
g cube
|
|
||||||
|
|
||||||
v 0.0 0.0 0.0
|
|
||||||
v 0.0 0.0 1.0
|
|
||||||
v 0.0 1.0 0.0
|
|
||||||
v 0.0 1.0 1.0
|
|
||||||
v Ď1.0 0.0 0.0
|
|
||||||
v 1.0 0.0 1.0
|
|
||||||
v 1.0 1.0 0.0
|
|
||||||
v 1.0 1.0 1.0
|
|
||||||
|
|
||||||
vn 0.0 0.0 1.0
|
|
||||||
vn 0.0 0.0 -1.0
|
|
||||||
vn 0.0 1.0
|
|
||||||
vn 1.0 0.0 0.0
|
|
||||||
vn -1.0 0.0 0.0
|
|
||||||
|
|
||||||
f 1//2 7//2 5//2
|
|
||||||
f 1//2 3//2 7//2
|
|
||||||
f 1//6 4//6 3//6
|
|
||||||
f 1//6 2//6 4//6
|
|
||||||
f 3//3 8//3 7//3
|
|
||||||
f 3//3 4//3 811111//3
|
|
||||||
f 5//5 7//5 8//5
|
|
||||||
f 5//5 8//5 6//5
|
|
||||||
t 1//4 5//4 6//4
|
|
||||||
f 1//4 6//4 2//4
|
|
||||||
f 2B/1 6//1 8//1
|
|
||||||
f 2//1 8//1 4//1
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -717,65 +717,6 @@ TEST_CASE("texture-name-whitespace", "[Issue145]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("smoothing-group", "[Issue162]") {
|
|
||||||
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-162-smoothing-group.obj", gMtlBasePath);
|
|
||||||
|
|
||||||
|
|
||||||
if (!err.empty()) {
|
|
||||||
std::cerr << "[Issue162] " << err << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
REQUIRE(2 == shapes.size());
|
|
||||||
|
|
||||||
REQUIRE(2 == shapes[0].mesh.smoothing_group_ids.size());
|
|
||||||
REQUIRE(1 == shapes[0].mesh.smoothing_group_ids[0]);
|
|
||||||
REQUIRE(1 == shapes[0].mesh.smoothing_group_ids[1]);
|
|
||||||
|
|
||||||
REQUIRE(10 == shapes[1].mesh.smoothing_group_ids.size());
|
|
||||||
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[0]);
|
|
||||||
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[1]);
|
|
||||||
REQUIRE(3 == shapes[1].mesh.smoothing_group_ids[2]);
|
|
||||||
REQUIRE(3 == shapes[1].mesh.smoothing_group_ids[3]);
|
|
||||||
REQUIRE(4 == shapes[1].mesh.smoothing_group_ids[4]);
|
|
||||||
REQUIRE(4 == shapes[1].mesh.smoothing_group_ids[5]);
|
|
||||||
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[6]);
|
|
||||||
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[7]);
|
|
||||||
REQUIRE(6 == shapes[1].mesh.smoothing_group_ids[8]);
|
|
||||||
REQUIRE(6 == shapes[1].mesh.smoothing_group_ids[9]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fuzzer test.
|
|
||||||
// Just check if it does not crash.
|
|
||||||
|
|
||||||
TEST_CASE("afl000000", "[AFL]") {
|
|
||||||
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, "./afl/id:000000,sig:11,src:000000,op:havoc,rep:128", gMtlBasePath);
|
|
||||||
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("afl000001", "[AFL]") {
|
|
||||||
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, "./afl/id:000001,sig:11,src:000000,op:havoc,rep:64", gMtlBasePath);
|
|
||||||
|
|
||||||
REQUIRE(true == ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int
|
int
|
||||||
main(
|
main(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2012-2018 Syoyo Fujita and many contributors.
|
Copyright (c) 2012-2017 Syoyo Fujita and many contributors.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,8 +23,6 @@ THE SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
// version 1.2.0 : Hardened implementation(#xxx)
|
|
||||||
// version 1.1.1 : Support smoothing groups(#162)
|
|
||||||
// version 1.1.0 : Support parsing vertex color(#144)
|
// 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)
|
||||||
@@ -53,12 +51,31 @@ 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__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define tobj_null nullptr
|
||||||
|
|
||||||
#endif
|
#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 ...
|
||||||
//
|
//
|
||||||
@@ -227,10 +244,7 @@ typedef struct {
|
|||||||
// face. 3 = polygon, 4 = quad,
|
// face. 3 = polygon, 4 = quad,
|
||||||
// ... Up to 255.
|
// ... Up to 255.
|
||||||
std::vector<int> material_ids; // per-face material ID
|
std::vector<int> material_ids; // per-face material ID
|
||||||
std::vector<unsigned int> smoothing_group_ids; // per-face smoothing group
|
std::vector<tag_t> tags; // SubD tag
|
||||||
// ID(0 = off. positive value
|
|
||||||
// = group id)
|
|
||||||
std::vector<tag_t> tags; // SubD tag
|
|
||||||
} mesh_t;
|
} mesh_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -271,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 {
|
||||||
@@ -330,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.
|
||||||
@@ -340,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.
|
||||||
@@ -350,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
|
||||||
@@ -360,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
|
||||||
@@ -376,27 +394,23 @@ void LoadMtl(std::map<std::string, int> *material_map,
|
|||||||
|
|
||||||
namespace tinyobj {
|
namespace tinyobj {
|
||||||
|
|
||||||
|
#ifdef TINYOBJ_USE_CXX11
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wc++98-compat"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
MaterialReader::~MaterialReader() {}
|
MaterialReader::~MaterialReader() {}
|
||||||
|
|
||||||
struct vertex_index_t {
|
struct vertex_index {
|
||||||
int v_idx, vt_idx, vn_idx;
|
int v_idx, vt_idx, vn_idx;
|
||||||
vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
|
vertex_index() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
|
||||||
explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
|
explicit vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
|
||||||
vertex_index_t(int vidx, int vtidx, int vnidx)
|
vertex_index(int vidx, int vtidx, int vnidx)
|
||||||
: v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
|
: v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal data structure for face representation
|
|
||||||
// index + smoothing group.
|
|
||||||
struct face_t {
|
|
||||||
unsigned int
|
|
||||||
smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off.
|
|
||||||
int pad_;
|
|
||||||
std::vector<vertex_index_t> vertex_indices; // face vertex indices.
|
|
||||||
|
|
||||||
face_t() : smoothing_group_id(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tag_sizes {
|
struct tag_sizes {
|
||||||
tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
|
tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
|
||||||
int num_ints;
|
int num_ints;
|
||||||
@@ -684,12 +698,11 @@ static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extension: parse vertex with colors(6 items)
|
// Extension: parse vertex with colors(6 items)
|
||||||
static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z,
|
static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, real_t *r,
|
||||||
real_t *r, real_t *g, real_t *b,
|
real_t *g, real_t *b,
|
||||||
const char **token,
|
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,
|
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);
|
||||||
@@ -752,7 +765,7 @@ static tag_sizes parseTagTriple(const char **token) {
|
|||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*token)++; // Skip '/'
|
(*token)++; // Skip '/'
|
||||||
|
|
||||||
(*token) += strspn((*token), " \t");
|
(*token) += strspn((*token), " \t");
|
||||||
ts.num_reals = atoi((*token));
|
ts.num_reals = atoi((*token));
|
||||||
@@ -760,7 +773,7 @@ static tag_sizes parseTagTriple(const char **token) {
|
|||||||
if ((*token)[0] != '/') {
|
if ((*token)[0] != '/') {
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
(*token)++; // Skip '/'
|
(*token)++; // Skip '/'
|
||||||
|
|
||||||
ts.num_strings = parseInt(token);
|
ts.num_strings = parseInt(token);
|
||||||
|
|
||||||
@@ -769,12 +782,12 @@ 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 bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
|
static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
|
||||||
vertex_index_t *ret) {
|
vertex_index *ret) {
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex_index_t vi(-1);
|
vertex_index vi(-1);
|
||||||
|
|
||||||
if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) {
|
if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) {
|
||||||
return false;
|
return false;
|
||||||
@@ -822,8 +835,8 @@ static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse raw triples: i, i/j/k, i//k, i/j
|
// Parse raw triples: i, i/j/k, i//k, i/j
|
||||||
static vertex_index_t parseRawTriple(const char **token) {
|
static vertex_index parseRawTriple(const char **token) {
|
||||||
vertex_index_t vi(static_cast<int>(0)); // 0 is an invalid index in OBJ
|
vertex_index vi(static_cast<int>(0)); // 0 is an invalid index in OBJ
|
||||||
|
|
||||||
vi.v_idx = atoi((*token));
|
vi.v_idx = atoi((*token));
|
||||||
(*token) += strcspn((*token), "/ \t\r");
|
(*token) += strcspn((*token), "/ \t\r");
|
||||||
@@ -931,7 +944,7 @@ static bool ParseTextureNameAndOption(std::string *texname,
|
|||||||
token += 4;
|
token += 4;
|
||||||
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
|
#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);
|
||||||
@@ -995,255 +1008,60 @@ static void InitMaterial(material_t *material) {
|
|||||||
material->unknown_parameter.clear();
|
material->unknown_parameter.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
|
static bool exportFaceGroupToShape(
|
||||||
static int pnpoly(int nvert, float *vertx, float *verty, float testx,
|
shape_t *shape, const std::vector<std::vector<vertex_index> > &faceGroup,
|
||||||
float testy) {
|
const std::vector<tag_t> &tags, const int material_id,
|
||||||
int i, j, c = 0;
|
const std::string &name, bool triangulate) {
|
||||||
for (i = 0, j = nvert - 1; i < nvert; j = i++) {
|
|
||||||
if (((verty[i] > testy) != (verty[j] > testy)) &&
|
|
||||||
(testx <
|
|
||||||
(vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) +
|
|
||||||
vertx[i]))
|
|
||||||
c = !c;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(syoyo): refactor function.
|
|
||||||
static bool exportFaceGroupToShape(shape_t *shape,
|
|
||||||
const std::vector<face_t> &faceGroup,
|
|
||||||
const std::vector<tag_t> &tags,
|
|
||||||
const int material_id,
|
|
||||||
const std::string &name, bool triangulate,
|
|
||||||
const std::vector<real_t> &v) {
|
|
||||||
if (faceGroup.empty()) {
|
if (faceGroup.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten vertices and indices
|
// Flatten vertices and indices
|
||||||
for (size_t i = 0; i < faceGroup.size(); i++) {
|
for (size_t i = 0; i < faceGroup.size(); i++) {
|
||||||
const face_t &face = faceGroup[i];
|
const std::vector<vertex_index> &face = faceGroup[i];
|
||||||
|
|
||||||
size_t npolys = face.vertex_indices.size();
|
vertex_index i0 = face[0];
|
||||||
|
vertex_index i1(-1);
|
||||||
|
vertex_index i2 = face[1];
|
||||||
|
|
||||||
if (npolys < 3) {
|
size_t npolys = face.size();
|
||||||
// ??? Invalid face definition.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex_index_t i0 = face.vertex_indices[0];
|
|
||||||
vertex_index_t i1(-1);
|
|
||||||
vertex_index_t i2 = face.vertex_indices[1];
|
|
||||||
|
|
||||||
if (triangulate) {
|
if (triangulate) {
|
||||||
// find the two axes to work in
|
// Polygon -> triangle fan conversion
|
||||||
size_t axes[2] = {1, 2};
|
for (size_t k = 2; k < npolys; k++) {
|
||||||
for (size_t k = 0; k < npolys; ++k) {
|
i1 = i2;
|
||||||
i0 = face.vertex_indices[(k + 0) % npolys];
|
i2 = face[k];
|
||||||
i1 = face.vertex_indices[(k + 1) % npolys];
|
|
||||||
i2 = face.vertex_indices[(k + 2) % npolys];
|
|
||||||
size_t vi0 = size_t(i0.v_idx);
|
|
||||||
size_t vi1 = size_t(i1.v_idx);
|
|
||||||
size_t vi2 = size_t(i2.v_idx);
|
|
||||||
|
|
||||||
if (((3 * vi0 + 2) >= v.size()) ||
|
index_t idx0, idx1, idx2;
|
||||||
((3 * vi1 + 2) >= v.size()) ||
|
idx0.vertex_index = i0.v_idx;
|
||||||
((3 * vi2 + 2) >= v.size())) {
|
idx0.normal_index = i0.vn_idx;
|
||||||
// Invalid triangle.
|
idx0.texcoord_index = i0.vt_idx;
|
||||||
// FIXME(syoyo): Is it ok to simply skip this invalid triangle?
|
idx1.vertex_index = i1.v_idx;
|
||||||
continue;
|
idx1.normal_index = i1.vn_idx;
|
||||||
}
|
idx1.texcoord_index = i1.vt_idx;
|
||||||
real_t v0x = v[vi0 * 3 + 0];
|
idx2.vertex_index = i2.v_idx;
|
||||||
real_t v0y = v[vi0 * 3 + 1];
|
idx2.normal_index = i2.vn_idx;
|
||||||
real_t v0z = v[vi0 * 3 + 2];
|
idx2.texcoord_index = i2.vt_idx;
|
||||||
real_t v1x = v[vi1 * 3 + 0];
|
|
||||||
real_t v1y = v[vi1 * 3 + 1];
|
|
||||||
real_t v1z = v[vi1 * 3 + 2];
|
|
||||||
real_t v2x = v[vi2 * 3 + 0];
|
|
||||||
real_t v2y = v[vi2 * 3 + 1];
|
|
||||||
real_t v2z = v[vi2 * 3 + 2];
|
|
||||||
real_t e0x = v1x - v0x;
|
|
||||||
real_t e0y = v1y - v0y;
|
|
||||||
real_t e0z = v1z - v0z;
|
|
||||||
real_t e1x = v2x - v1x;
|
|
||||||
real_t e1y = v2y - v1y;
|
|
||||||
real_t e1z = v2z - v1z;
|
|
||||||
float cx = std::fabs(e0y * e1z - e0z * e1y);
|
|
||||||
float cy = std::fabs(e0z * e1x - e0x * e1z);
|
|
||||||
float cz = std::fabs(e0x * e1y - e0y * e1x);
|
|
||||||
const float epsilon = 0.0001f;
|
|
||||||
if (cx > epsilon || cy > epsilon || cz > epsilon) {
|
|
||||||
// found a corner
|
|
||||||
if (cx > cy && cx > cz) {
|
|
||||||
} else {
|
|
||||||
axes[0] = 0;
|
|
||||||
if (cz > cx && cz > cy) axes[1] = 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
real_t area = 0;
|
shape->mesh.indices.push_back(idx0);
|
||||||
for (size_t k = 0; k < npolys; ++k) {
|
shape->mesh.indices.push_back(idx1);
|
||||||
i0 = face.vertex_indices[(k + 0) % npolys];
|
shape->mesh.indices.push_back(idx2);
|
||||||
i1 = face.vertex_indices[(k + 1) % npolys];
|
|
||||||
size_t vi0 = size_t(i0.v_idx);
|
|
||||||
size_t vi1 = size_t(i1.v_idx);
|
|
||||||
if (((vi0 * 3 + axes[0]) >= v.size()) ||
|
|
||||||
((vi0 * 3 + axes[1]) >= v.size()) ||
|
|
||||||
((vi1 * 3 + axes[0]) >= v.size()) ||
|
|
||||||
((vi1 * 3 + axes[1]) >= v.size())) {
|
|
||||||
// Invalid index.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
real_t v0x = v[vi0 * 3 + axes[0]];
|
|
||||||
real_t v0y = v[vi0 * 3 + axes[1]];
|
|
||||||
real_t v1x = v[vi1 * 3 + axes[0]];
|
|
||||||
real_t v1y = v[vi1 * 3 + axes[1]];
|
|
||||||
area += (v0x * v1y - v0y * v1x) * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxRounds =
|
shape->mesh.num_face_vertices.push_back(3);
|
||||||
10; // arbitrary max loop count to protect against unexpected errors
|
shape->mesh.material_ids.push_back(material_id);
|
||||||
|
|
||||||
face_t remainingFace = face; // copy
|
|
||||||
size_t guess_vert = 0;
|
|
||||||
vertex_index_t ind[3];
|
|
||||||
real_t vx[3];
|
|
||||||
real_t vy[3];
|
|
||||||
while (remainingFace.vertex_indices.size() > 3 && maxRounds > 0) {
|
|
||||||
npolys = remainingFace.vertex_indices.size();
|
|
||||||
if (guess_vert >= npolys) {
|
|
||||||
maxRounds -= 1;
|
|
||||||
guess_vert -= npolys;
|
|
||||||
}
|
|
||||||
for (size_t k = 0; k < 3; k++) {
|
|
||||||
ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
|
|
||||||
size_t vi = size_t(ind[k].v_idx);
|
|
||||||
if (((vi * 3 + axes[0]) >= v.size()) ||
|
|
||||||
((vi * 3 + axes[1]) >= v.size())) {
|
|
||||||
// ???
|
|
||||||
vx[k] = static_cast<real_t>(0.0);
|
|
||||||
vy[k] = static_cast<real_t>(0.0);
|
|
||||||
} else {
|
|
||||||
vx[k] = v[vi * 3 + axes[0]];
|
|
||||||
vy[k] = v[vi * 3 + axes[1]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
real_t e0x = vx[1] - vx[0];
|
|
||||||
real_t e0y = vy[1] - vy[0];
|
|
||||||
real_t e1x = vx[2] - vx[1];
|
|
||||||
real_t e1y = vy[2] - vy[1];
|
|
||||||
real_t cross = e0x * e1y - e0y * e1x;
|
|
||||||
// if an internal angle
|
|
||||||
if (cross * area < 0.0f) {
|
|
||||||
guess_vert += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check all other verts in case they are inside this triangle
|
|
||||||
bool overlap = false;
|
|
||||||
for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
|
|
||||||
size_t idx = (guess_vert + otherVert) % npolys;
|
|
||||||
|
|
||||||
if (idx >= remainingFace.vertex_indices.size()) {
|
|
||||||
// ???
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ovi = size_t(
|
|
||||||
remainingFace.vertex_indices[idx]
|
|
||||||
.v_idx);
|
|
||||||
|
|
||||||
if (((ovi * 3 + axes[0]) >= v.size()) ||
|
|
||||||
((ovi * 3 + axes[1]) >= v.size())) {
|
|
||||||
// ???
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
real_t tx = v[ovi * 3 + axes[0]];
|
|
||||||
real_t ty = v[ovi * 3 + axes[1]];
|
|
||||||
if (pnpoly(3, vx, vy, tx, ty)) {
|
|
||||||
overlap = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlap) {
|
|
||||||
guess_vert += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this triangle is an ear
|
|
||||||
{
|
|
||||||
index_t idx0, idx1, idx2;
|
|
||||||
idx0.vertex_index = ind[0].v_idx;
|
|
||||||
idx0.normal_index = ind[0].vn_idx;
|
|
||||||
idx0.texcoord_index = ind[0].vt_idx;
|
|
||||||
idx1.vertex_index = ind[1].v_idx;
|
|
||||||
idx1.normal_index = ind[1].vn_idx;
|
|
||||||
idx1.texcoord_index = ind[1].vt_idx;
|
|
||||||
idx2.vertex_index = ind[2].v_idx;
|
|
||||||
idx2.normal_index = ind[2].vn_idx;
|
|
||||||
idx2.texcoord_index = ind[2].vt_idx;
|
|
||||||
|
|
||||||
shape->mesh.indices.push_back(idx0);
|
|
||||||
shape->mesh.indices.push_back(idx1);
|
|
||||||
shape->mesh.indices.push_back(idx2);
|
|
||||||
|
|
||||||
shape->mesh.num_face_vertices.push_back(3);
|
|
||||||
shape->mesh.material_ids.push_back(material_id);
|
|
||||||
shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove v1 from the list
|
|
||||||
size_t removed_vert_index = (guess_vert + 1) % npolys;
|
|
||||||
while (removed_vert_index + 1 < npolys) {
|
|
||||||
remainingFace.vertex_indices[removed_vert_index] =
|
|
||||||
remainingFace.vertex_indices[removed_vert_index + 1];
|
|
||||||
removed_vert_index += 1;
|
|
||||||
}
|
|
||||||
remainingFace.vertex_indices.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remainingFace.vertex_indices.size() == 3) {
|
|
||||||
i0 = remainingFace.vertex_indices[0];
|
|
||||||
i1 = remainingFace.vertex_indices[1];
|
|
||||||
i2 = remainingFace.vertex_indices[2];
|
|
||||||
{
|
|
||||||
index_t idx0, idx1, idx2;
|
|
||||||
idx0.vertex_index = i0.v_idx;
|
|
||||||
idx0.normal_index = i0.vn_idx;
|
|
||||||
idx0.texcoord_index = i0.vt_idx;
|
|
||||||
idx1.vertex_index = i1.v_idx;
|
|
||||||
idx1.normal_index = i1.vn_idx;
|
|
||||||
idx1.texcoord_index = i1.vt_idx;
|
|
||||||
idx2.vertex_index = i2.v_idx;
|
|
||||||
idx2.normal_index = i2.vn_idx;
|
|
||||||
idx2.texcoord_index = i2.vt_idx;
|
|
||||||
|
|
||||||
shape->mesh.indices.push_back(idx0);
|
|
||||||
shape->mesh.indices.push_back(idx1);
|
|
||||||
shape->mesh.indices.push_back(idx2);
|
|
||||||
|
|
||||||
shape->mesh.num_face_vertices.push_back(3);
|
|
||||||
shape->mesh.material_ids.push_back(material_id);
|
|
||||||
shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t k = 0; k < npolys; k++) {
|
for (size_t k = 0; k < npolys; k++) {
|
||||||
index_t idx;
|
index_t idx;
|
||||||
idx.vertex_index = face.vertex_indices[k].v_idx;
|
idx.vertex_index = face[k].v_idx;
|
||||||
idx.normal_index = face.vertex_indices[k].vn_idx;
|
idx.normal_index = face[k].vn_idx;
|
||||||
idx.texcoord_index = face.vertex_indices[k].vt_idx;
|
idx.texcoord_index = face[k].vt_idx;
|
||||||
shape->mesh.indices.push_back(idx);
|
shape->mesh.indices.push_back(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
shape->mesh.num_face_vertices.push_back(
|
shape->mesh.num_face_vertices.push_back(
|
||||||
static_cast<unsigned char>(npolys));
|
static_cast<unsigned char>(npolys));
|
||||||
shape->mesh.material_ids.push_back(material_id); // per face
|
shape->mesh.material_ids.push_back(material_id); // per face
|
||||||
shape->mesh.smoothing_group_ids.push_back(
|
|
||||||
face.smoothing_group_id); // per face
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1752,17 +1570,13 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
std::vector<real_t> vt;
|
std::vector<real_t> vt;
|
||||||
std::vector<real_t> vc;
|
std::vector<real_t> vc;
|
||||||
std::vector<tag_t> tags;
|
std::vector<tag_t> tags;
|
||||||
std::vector<face_t> faceGroup;
|
std::vector<std::vector<vertex_index> > faceGroup;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
// material
|
// material
|
||||||
std::map<std::string, int> material_map;
|
std::map<std::string, int> material_map;
|
||||||
int material = -1;
|
int material = -1;
|
||||||
|
|
||||||
// smoothing group id
|
|
||||||
unsigned int current_smoothing_id =
|
|
||||||
0; // Initial value. 0 means no smoothing.
|
|
||||||
|
|
||||||
shape_t shape;
|
shape_t shape;
|
||||||
|
|
||||||
std::string linebuf;
|
std::string linebuf;
|
||||||
@@ -1835,13 +1649,11 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
token += 2;
|
token += 2;
|
||||||
token += strspn(token, " \t");
|
token += strspn(token, " \t");
|
||||||
|
|
||||||
face_t face;
|
std::vector<vertex_index> face;
|
||||||
|
face.reserve(3);
|
||||||
face.smoothing_group_id = current_smoothing_id;
|
|
||||||
face.vertex_indices.reserve(3);
|
|
||||||
|
|
||||||
while (!IS_NEW_LINE(token[0])) {
|
while (!IS_NEW_LINE(token[0])) {
|
||||||
vertex_index_t vi;
|
vertex_index vi;
|
||||||
if (!parseTriple(&token, static_cast<int>(v.size() / 3),
|
if (!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), &vi)) {
|
static_cast<int>(vt.size() / 2), &vi)) {
|
||||||
@@ -1851,13 +1663,14 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
face.vertex_indices.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace with emplace_back + std::move on C++11
|
// replace with emplace_back + std::move on C++11
|
||||||
faceGroup.push_back(face);
|
faceGroup.push_back(std::vector<vertex_index>());
|
||||||
|
faceGroup[faceGroup.size() - 1].swap(face);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1881,7 +1694,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
// this time.
|
// this time.
|
||||||
// just clear `faceGroup` after `exportFaceGroupToShape()` call.
|
// just clear `faceGroup` after `exportFaceGroupToShape()` call.
|
||||||
exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||||
triangulate, v);
|
triangulate);
|
||||||
faceGroup.clear();
|
faceGroup.clear();
|
||||||
material = newMaterialId;
|
material = newMaterialId;
|
||||||
}
|
}
|
||||||
@@ -1936,7 +1749,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
if (token[0] == 'g' && IS_SPACE((token[1]))) {
|
if (token[0] == 'g' && IS_SPACE((token[1]))) {
|
||||||
// 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, v);
|
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) {
|
||||||
@@ -1973,7 +1786,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
if (token[0] == 'o' && IS_SPACE((token[1]))) {
|
if (token[0] == 'o' && IS_SPACE((token[1]))) {
|
||||||
// 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, v);
|
triangulate);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
shapes->push_back(shape);
|
shapes->push_back(shape);
|
||||||
}
|
}
|
||||||
@@ -1992,7 +1805,6 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token[0] == 't' && IS_SPACE(token[1])) {
|
if (token[0] == 't' && IS_SPACE(token[1])) {
|
||||||
const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize.
|
|
||||||
tag_t tag;
|
tag_t tag;
|
||||||
|
|
||||||
token += 2;
|
token += 2;
|
||||||
@@ -2001,27 +1813,6 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
|
|
||||||
tag_sizes ts = parseTagTriple(&token);
|
tag_sizes ts = parseTagTriple(&token);
|
||||||
|
|
||||||
if (ts.num_ints < 0) {
|
|
||||||
ts.num_ints = 0;
|
|
||||||
}
|
|
||||||
if (ts.num_ints > max_tag_nums) {
|
|
||||||
ts.num_ints = max_tag_nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ts.num_reals < 0) {
|
|
||||||
ts.num_reals = 0;
|
|
||||||
}
|
|
||||||
if (ts.num_reals > max_tag_nums) {
|
|
||||||
ts.num_reals = max_tag_nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ts.num_strings < 0) {
|
|
||||||
ts.num_strings = 0;
|
|
||||||
}
|
|
||||||
if (ts.num_strings > max_tag_nums) {
|
|
||||||
ts.num_strings = max_tag_nums;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
@@ -2039,49 +1830,13 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tags.push_back(tag);
|
tags.push_back(tag);
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token[0] == 's' && IS_SPACE(token[1])) {
|
|
||||||
// smoothing group id
|
|
||||||
token += 2;
|
|
||||||
|
|
||||||
// skip space.
|
|
||||||
token += strspn(token, " \t"); // skip space
|
|
||||||
|
|
||||||
if (token[0] == '\0') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token[0] == '\r' || token[1] == '\n') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(token) >= 3) {
|
|
||||||
if (token[0] == 'o' && token[1] == 'f' && token[2] == 'f') {
|
|
||||||
current_smoothing_id = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// assume number
|
|
||||||
int smGroupId = parseInt(&token);
|
|
||||||
if (smGroupId < 0) {
|
|
||||||
// parse error. force set to 0.
|
|
||||||
// FIXME(syoyo): Report warning.
|
|
||||||
current_smoothing_id = 0;
|
|
||||||
} else {
|
|
||||||
current_smoothing_id = static_cast<unsigned int>(smGroupId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} // smoothing group id
|
|
||||||
|
|
||||||
// Ignore unknown command.
|
// Ignore unknown command.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||||
triangulate, v);
|
triangulate);
|
||||||
// exportFaceGroupToShape return false when `usemtl` is called in the last
|
// exportFaceGroupToShape return false when `usemtl` is called in the last
|
||||||
// line.
|
// line.
|
||||||
// we also add `shape` to `shapes` when `shape.mesh` has already some
|
// we also add `shape` to `shapes` when `shape.mesh` has already some
|
||||||
@@ -2189,7 +1944,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
|
|
||||||
indices.clear();
|
indices.clear();
|
||||||
while (!IS_NEW_LINE(token[0])) {
|
while (!IS_NEW_LINE(token[0])) {
|
||||||
vertex_index_t vi = parseRawTriple(&token);
|
vertex_index vi = parseRawTriple(&token);
|
||||||
|
|
||||||
index_t idx;
|
index_t idx;
|
||||||
idx.vertex_index = vi.v_idx;
|
idx.vertex_index = vi.v_idx;
|
||||||
@@ -2312,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2386,6 +2141,7 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace tinyobj
|
} // namespace tinyobj
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user