Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2daec8be53 | ||
|
|
c2ff3f12fc | ||
|
|
e0b39341fc | ||
|
|
947582b592 | ||
|
|
c207ff3561 | ||
|
|
41dd7c806e | ||
|
|
aa4dabe64f | ||
|
|
9868630d0e | ||
|
|
f2397573f3 | ||
|
|
7d5699118e | ||
|
|
0948ca0417 | ||
|
|
582eb2b818 | ||
|
|
c2474e27ab | ||
|
|
6c6390f034 | ||
|
|
4d6649cc6d | ||
|
|
d543b1447f | ||
|
|
d6eeb14216 | ||
|
|
aa670fe91e | ||
|
|
ebdbd8a231 |
@@ -143,7 +143,26 @@ float eye[3], lookat[3], up[3];
|
|||||||
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
|
||||||
void CheckErrors(std::string desc) {
|
static std::string GetBaseDir(const std::string &filepath) {
|
||||||
|
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||||
|
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool FileExists(const std::string &abs_filename) {
|
||||||
|
bool ret;
|
||||||
|
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||||
|
if (fp) {
|
||||||
|
ret = true;
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckErrors(std::string desc) {
|
||||||
GLenum e = glGetError();
|
GLenum e = glGetError();
|
||||||
if (e != GL_NO_ERROR) {
|
if (e != GL_NO_ERROR) {
|
||||||
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
|
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
|
||||||
@@ -151,7 +170,7 @@ void CheckErrors(std::string desc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
||||||
float v10[3];
|
float v10[3];
|
||||||
v10[0] = v1[0] - v0[0];
|
v10[0] = v1[0] - v0[0];
|
||||||
v10[1] = v1[1] - v0[1];
|
v10[1] = v1[1] - v0[1];
|
||||||
@@ -175,7 +194,7 @@ void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@@ -187,9 +206,16 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
|
|
||||||
tm.start();
|
tm.start();
|
||||||
|
|
||||||
|
std::string base_dir = GetBaseDir(filename);
|
||||||
|
#ifdef _WIN32
|
||||||
|
base_dir += "\\";
|
||||||
|
#else
|
||||||
|
base_dir += "/";
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
bool ret =
|
bool ret =
|
||||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, NULL);
|
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;
|
||||||
}
|
}
|
||||||
@@ -209,6 +235,9 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
printf("# of materials = %d\n", (int)materials.size());
|
printf("# of materials = %d\n", (int)materials.size());
|
||||||
printf("# of shapes = %d\n", (int)shapes.size());
|
printf("# of shapes = %d\n", (int)shapes.size());
|
||||||
|
|
||||||
|
// Append `default` material
|
||||||
|
materials.push_back(tinyobj::material_t());
|
||||||
|
|
||||||
// Load diffuse textures
|
// Load diffuse textures
|
||||||
{
|
{
|
||||||
for (size_t m = 0; m < materials.size(); m++) {
|
for (size_t m = 0; m < materials.size(); m++) {
|
||||||
@@ -220,9 +249,20 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
GLuint texture_id;
|
GLuint texture_id;
|
||||||
int w, h;
|
int w, h;
|
||||||
int comp;
|
int comp;
|
||||||
unsigned char* image = stbi_load(mp->diffuse_texname.c_str(), &w, &h, &comp, STBI_default);
|
|
||||||
|
std::string texture_filename = mp->diffuse_texname;
|
||||||
|
if (!FileExists(texture_filename)) {
|
||||||
|
// Append base dir.
|
||||||
|
texture_filename = base_dir + mp->diffuse_texname;
|
||||||
|
if (!FileExists(texture_filename)) {
|
||||||
|
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 == nullptr) {
|
if (image == nullptr) {
|
||||||
std::cerr << "Unable to load texture: " << mp->diffuse_texname << std::endl;
|
std::cerr << "Unable to load texture: " << texture_filename << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
glGenTextures(1, &texture_id);
|
glGenTextures(1, &texture_id);
|
||||||
@@ -248,11 +288,6 @@ 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++) {
|
||||||
size_t current_material_id = 0;
|
|
||||||
if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
|
|
||||||
// Base case
|
|
||||||
current_material_id = shapes[s].mesh.material_ids[s];
|
|
||||||
}
|
|
||||||
DrawObject o;
|
DrawObject o;
|
||||||
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
|
||||||
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++) {
|
||||||
@@ -260,12 +295,16 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
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];
|
||||||
|
|
||||||
current_material_id = shapes[s].mesh.material_ids[f];
|
int current_material_id = shapes[s].mesh.material_ids[f];
|
||||||
|
|
||||||
if (current_material_id >= materials.size()) {
|
if ((current_material_id < 0) || (current_material_id >= static_cast<int>(materials.size()))) {
|
||||||
std::cerr << "Invalid material index: " << current_material_id << std::endl;
|
// Invaid material ID. Use default material.
|
||||||
|
current_material_id = materials.size() - 1; // Default material is added to the last item in `materials`.
|
||||||
}
|
}
|
||||||
|
//if (current_material_id >= materials.size()) {
|
||||||
|
// std::cerr << "Invalid material index: " << current_material_id << 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];
|
||||||
@@ -364,7 +403,15 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
|
|
||||||
o.vb = 0;
|
o.vb = 0;
|
||||||
o.numTriangles = 0;
|
o.numTriangles = 0;
|
||||||
o.material_id = current_material_id;
|
|
||||||
|
// OpenGL viewer does not support texturing with per-face material.
|
||||||
|
if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
|
||||||
|
// Base case
|
||||||
|
o.material_id = shapes[s].mesh.material_ids[s];
|
||||||
|
} else {
|
||||||
|
o.material_id = materials.size() - 1; // = ID for default material.
|
||||||
|
}
|
||||||
|
|
||||||
if (vb.size() > 0) {
|
if (vb.size() > 0) {
|
||||||
glGenBuffers(1, &o.vb);
|
glGenBuffers(1, &o.vb);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
|
||||||
@@ -385,7 +432,7 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reshapeFunc(GLFWwindow* window, int w, int h) {
|
static void reshapeFunc(GLFWwindow* window, int w, int h) {
|
||||||
int fb_w, fb_h;
|
int fb_w, fb_h;
|
||||||
// Get actual framebuffer size.
|
// Get actual framebuffer size.
|
||||||
glfwGetFramebufferSize(window, &fb_w, &fb_h);
|
glfwGetFramebufferSize(window, &fb_w, &fb_h);
|
||||||
@@ -401,7 +448,7 @@ void reshapeFunc(GLFWwindow* window, int w, int h) {
|
|||||||
height = h;
|
height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -430,7 +477,7 @@ void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clickFunc(GLFWwindow* window, int button, int action, int mods) {
|
static void clickFunc(GLFWwindow* window, int button, int action, int mods) {
|
||||||
(void)window;
|
(void)window;
|
||||||
(void)mods;
|
(void)mods;
|
||||||
if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||||
@@ -457,7 +504,7 @@ void clickFunc(GLFWwindow* window, int button, int action, int mods) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
||||||
(void)window;
|
(void)window;
|
||||||
float rotScale = 1.0f;
|
float rotScale = 1.0f;
|
||||||
float transScale = 2.0f;
|
float transScale = 2.0f;
|
||||||
@@ -484,7 +531,7 @@ void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
|||||||
prevMouseY = mouse_y;
|
prevMouseY = mouse_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t>& materials, std::map<std::string, GLuint>& textures) {
|
static void Draw(const std::vector<DrawObject>& drawObjects, 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);
|
||||||
|
|
||||||
@@ -503,9 +550,11 @@ void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::mater
|
|||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
if ((o.material_id < materials.size())) {
|
||||||
if (diffuse_texname.length() > 0) {
|
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
if (textures.find(diffuse_texname) != textures.end()) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||||
|
|||||||
74
examples/voxelize/main.cc
Normal file
74
examples/voxelize/main.cc
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#define VOXELIZER_IMPLEMENTATION
|
||||||
|
#include "voxelizer.h"
|
||||||
|
|
||||||
|
#define TINYOBJLOADER_IMPLEMENTATION
|
||||||
|
#include "../../tiny_obj_loader.h"
|
||||||
|
|
||||||
|
bool Voxelize(const char* filename, float voxelsizex, float voxelsizey, float voxelsizez, float precision)
|
||||||
|
{
|
||||||
|
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, filename);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
printf("err: %s\n", err.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
printf("failed to load : %s\n", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shapes.size() == 0) {
|
||||||
|
printf("err: # of shapes are zero.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only use first shape.
|
||||||
|
{
|
||||||
|
vx_mesh_t* mesh;
|
||||||
|
vx_mesh_t* result;
|
||||||
|
|
||||||
|
mesh = vx_mesh_alloc(attrib.vertices.size(), shapes[0].mesh.indices.size());
|
||||||
|
|
||||||
|
for (size_t f = 0; f < shapes[0].mesh.indices.size(); f++) {
|
||||||
|
mesh->indices[f] = shapes[0].mesh.indices[f].vertex_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
|
||||||
|
mesh->vertices[v].x = attrib.vertices[3*v+0];
|
||||||
|
mesh->vertices[v].y = attrib.vertices[3*v+1];
|
||||||
|
mesh->vertices[v].z = attrib.vertices[3*v+2];
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vx_voxelize(mesh, voxelsizex, voxelsizey, voxelsizez, precision);
|
||||||
|
|
||||||
|
printf("Number of vertices: %ld\n", result->nvertices);
|
||||||
|
printf("Number of indices: %ld\n", result->nindices);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(
|
||||||
|
int argc,
|
||||||
|
char** argv)
|
||||||
|
{
|
||||||
|
if (argc < 4) {
|
||||||
|
printf("Usage: voxelize input.obj voxelsizex voxelsizey voxelsizez precision\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* filename = argv[1];
|
||||||
|
float voxelsizex = atof(argv[2]);
|
||||||
|
float voxelsizey = atof(argv[3]);
|
||||||
|
float voxelsizez = atof(argv[4]);
|
||||||
|
float prec = atof(argv[5]);
|
||||||
|
bool ret = Voxelize(filename, voxelsizex, voxelsizey, voxelsizez, prec);
|
||||||
|
|
||||||
|
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#include <mmsystem.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -233,16 +233,17 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
|
|||||||
printf(" material.map_Ns = %s\n",
|
printf(" material.map_Ns = %s\n",
|
||||||
materials[i].specular_highlight_texname.c_str());
|
materials[i].specular_highlight_texname.c_str());
|
||||||
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
|
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
|
||||||
|
printf(" bump_multiplier = %f\n", static_cast<const double>(materials[i].bump_texopt.bump_multiplier));
|
||||||
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
|
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
|
||||||
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
|
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
|
||||||
printf(" <<PBR>>\n");
|
printf(" <<PBR>>\n");
|
||||||
printf(" material.Pr = %f\n", materials[i].roughness);
|
printf(" material.Pr = %f\n", static_cast<const double>(materials[i].roughness));
|
||||||
printf(" material.Pm = %f\n", materials[i].metallic);
|
printf(" material.Pm = %f\n", static_cast<const double>(materials[i].metallic));
|
||||||
printf(" material.Ps = %f\n", materials[i].sheen);
|
printf(" material.Ps = %f\n", static_cast<const double>(materials[i].sheen));
|
||||||
printf(" material.Pc = %f\n", materials[i].clearcoat_thickness);
|
printf(" material.Pc = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
|
||||||
printf(" material.Pcr = %f\n", materials[i].clearcoat_thickness);
|
printf(" material.Pcr = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
|
||||||
printf(" material.aniso = %f\n", materials[i].anisotropy);
|
printf(" material.aniso = %f\n", static_cast<const double>(materials[i].anisotropy));
|
||||||
printf(" material.anisor = %f\n", materials[i].anisotropy_rotation);
|
printf(" material.anisor = %f\n", static_cast<const double>(materials[i].anisotropy_rotation));
|
||||||
printf(" material.map_Ke = %s\n", materials[i].emissive_texname.c_str());
|
printf(" material.map_Ke = %s\n", materials[i].emissive_texname.c_str());
|
||||||
printf(" material.map_Pr = %s\n", materials[i].roughness_texname.c_str());
|
printf(" material.map_Pr = %s\n", materials[i].roughness_texname.c_str());
|
||||||
printf(" material.map_Pm = %s\n", materials[i].metallic_texname.c_str());
|
printf(" material.map_Pm = %s\n", materials[i].metallic_texname.c_str());
|
||||||
|
|||||||
6
models/mtllib-multiple-files-issue-112.mtl
Normal file
6
models/mtllib-multiple-files-issue-112.mtl
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
newmtl default
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 0 0
|
||||||
|
Ks 0 0 0
|
||||||
|
map_Kd tmp.png
|
||||||
|
|
||||||
7
models/mtllib-multiple-files-issue-112.obj
Normal file
7
models/mtllib-multiple-files-issue-112.obj
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mtllib invalid-file-aaa.mtl invalid-file-bbb.mtl mtllib-multiple-files-issue-112.mtl
|
||||||
|
o Test
|
||||||
|
v 1.864151 -1.219172 -5.532511
|
||||||
|
v 0.575869 -0.666304 5.896140
|
||||||
|
v 0.940448 1.000000 -1.971128
|
||||||
|
usemtl default
|
||||||
|
f 1 2 3
|
||||||
36
models/texture-options-issue-85.mtl
Normal file
36
models/texture-options-issue-85.mtl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
newmtl default
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 0 0
|
||||||
|
Ks 0 0 0
|
||||||
|
Kt 0.1 0.2 0.3
|
||||||
|
map_Ka -clamp on ambient.jpg
|
||||||
|
map_Kd -o 0.1 diffuse.jpg
|
||||||
|
map_Ks -s 0.1 0.2 specular.jpg
|
||||||
|
map_Ns -t 0.1 0.2 0.3 specular_highlight.jpg
|
||||||
|
map_bump -bm 3 bumpmap.jpg
|
||||||
|
|
||||||
|
newmtl bm2
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 0 0
|
||||||
|
Ks 0 0 0
|
||||||
|
Kt 0.1 0.2 0.3
|
||||||
|
# blendu
|
||||||
|
map_Kd -blendu on diffuse.jpg
|
||||||
|
map_Ks -blendv off specular.jpg
|
||||||
|
map_Ns -mm 0.1 0.3 specular_highlight.jpg
|
||||||
|
# -bm after filename
|
||||||
|
map_bump -imfchan r bumpmap2.jpg -bm 1.5
|
||||||
|
|
||||||
|
newmtl bm3
|
||||||
|
Ka 0 0 0
|
||||||
|
Kd 0 0 0
|
||||||
|
Ks 0 0 0
|
||||||
|
Kt 0.1 0.2 0.3
|
||||||
|
# type
|
||||||
|
map_Kd -type sphere diffuse.jpg
|
||||||
|
map_Ks -type cube_top specular.jpg
|
||||||
|
map_Ns -type cube_bottom specular_highlight.jpg
|
||||||
|
map_Ka -type cube_left ambient.jpg
|
||||||
|
map_d -type cube_right alpha.jpg
|
||||||
|
map_bump -type cube_front bump.jpg
|
||||||
|
disp -type cube_back displacement.jpg
|
||||||
7
models/texture-options-issue-85.obj
Normal file
7
models/texture-options-issue-85.obj
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mtllib texture-options-issue-85.mtl
|
||||||
|
o Test
|
||||||
|
v 1.864151 -1.219172 -5.532511
|
||||||
|
v 0.575869 -0.666304 5.896140
|
||||||
|
v 0.940448 1.000000 -1.971128
|
||||||
|
usemtl default
|
||||||
|
f 1 2 3
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
* PBR material
|
* PBR material
|
||||||
* Define index_t struct
|
* Define index_t struct
|
||||||
* Python 2.7 binding
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// python3 module for tinyobjloader
|
// python2/3 module for tinyobjloader
|
||||||
//
|
//
|
||||||
// usage:
|
// usage:
|
||||||
// import tinyobjloader as tol
|
// import tinyobjloader as tol
|
||||||
@@ -172,6 +172,7 @@ static PyObject* pyLoadObj(PyObject* self, PyObject* args) {
|
|||||||
|
|
||||||
PyDict_SetItemString(rtndict, "shapes", pyshapes);
|
PyDict_SetItemString(rtndict, "shapes", pyshapes);
|
||||||
PyDict_SetItemString(rtndict, "materials", pymaterials);
|
PyDict_SetItemString(rtndict, "materials", pymaterials);
|
||||||
|
PyDict_SetItemString(rtndict, "attribs", attribobj);
|
||||||
|
|
||||||
return rtndict;
|
return rtndict;
|
||||||
}
|
}
|
||||||
@@ -182,10 +183,21 @@ static PyMethodDef mMethods[] = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
|
||||||
static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "tinyobjloader",
|
static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "tinyobjloader",
|
||||||
NULL, -1, mMethods};
|
NULL, -1, mMethods};
|
||||||
|
|
||||||
PyMODINIT_FUNC PyInit_tinyobjloader(void) {
|
PyMODINIT_FUNC PyInit_tinyobjloader(void) {
|
||||||
return PyModule_Create(&moduledef);
|
return PyModule_Create(&moduledef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
PyMODINIT_FUNC inittinyobjloader(void) {
|
||||||
|
Py_InitModule3("tinyobjloader", mMethods, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PY_MAJOR_VERSION >= 3
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -488,6 +488,63 @@ TEST_CASE("usemtl_at_last_line", "[Issue104]") {
|
|||||||
REQUIRE(1 == shapes.size());
|
REQUIRE(1 == shapes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("texture_opts", "[Issue85]") {
|
||||||
|
tinyobj::attrib_t attrib;
|
||||||
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
|
||||||
|
std::string err;
|
||||||
|
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/texture-options-issue-85.obj", gMtlBasePath);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
REQUIRE(1 == shapes.size());
|
||||||
|
REQUIRE(3 == materials.size());
|
||||||
|
REQUIRE(0 == materials[0].name.compare("default"));
|
||||||
|
REQUIRE(0 == materials[1].name.compare("bm2"));
|
||||||
|
REQUIRE(0 == materials[2].name.compare("bm3"));
|
||||||
|
REQUIRE(true == materials[0].ambient_texopt.clamp);
|
||||||
|
REQUIRE(0.1 == Approx(materials[0].diffuse_texopt.origin_offset[0]));
|
||||||
|
REQUIRE(0.0 == Approx(materials[0].diffuse_texopt.origin_offset[1]));
|
||||||
|
REQUIRE(0.0 == Approx(materials[0].diffuse_texopt.origin_offset[2]));
|
||||||
|
REQUIRE(0.1 == Approx(materials[0].specular_texopt.scale[0]));
|
||||||
|
REQUIRE(0.2 == Approx(materials[0].specular_texopt.scale[1]));
|
||||||
|
REQUIRE(1.0 == Approx(materials[0].specular_texopt.scale[2]));
|
||||||
|
REQUIRE(0.1 == Approx(materials[0].specular_highlight_texopt.turbulence[0]));
|
||||||
|
REQUIRE(0.2 == Approx(materials[0].specular_highlight_texopt.turbulence[1]));
|
||||||
|
REQUIRE(0.3 == Approx(materials[0].specular_highlight_texopt.turbulence[2]));
|
||||||
|
REQUIRE(3.0 == Approx(materials[0].bump_texopt.bump_multiplier));
|
||||||
|
|
||||||
|
REQUIRE(0.1 == Approx(materials[1].specular_highlight_texopt.brightness));
|
||||||
|
REQUIRE(0.3 == Approx(materials[1].specular_highlight_texopt.contrast));
|
||||||
|
REQUIRE('r' == materials[1].bump_texopt.imfchan);
|
||||||
|
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_SPHERE == materials[2].diffuse_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_TOP == materials[2].specular_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_BOTTOM == materials[2].specular_highlight_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_LEFT == materials[2].ambient_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_RIGHT == materials[2].alpha_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_FRONT == materials[2].bump_texopt.type);
|
||||||
|
REQUIRE(tinyobj::TEXTURE_TYPE_CUBE_BACK == materials[2].displacement_texopt.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("mtllib_multiple_filenames", "[Issue112]") {
|
||||||
|
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/mtllib-multiple-files-issue-112.obj", gMtlBasePath);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
REQUIRE(1 == materials.size());
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int
|
int
|
||||||
main(
|
main(
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ THE SOFTWARE.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// version 1.0.4 : Support multiple filenames for 'mtllib'(#112)
|
||||||
|
// version 1.0.3 : Support parsing texture options(#85)
|
||||||
|
// version 1.0.2 : Improve parsing speed by about a factor of 2 for large
|
||||||
|
// files(#105)
|
||||||
// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104)
|
// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104)
|
||||||
// version 1.0.0 : Change data structure. Change license from BSD to MIT.
|
// version 1.0.0 : Change data structure. Change license from BSD to MIT.
|
||||||
//
|
//
|
||||||
@@ -42,6 +46,82 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
namespace tinyobj {
|
namespace tinyobj {
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ...
|
||||||
|
//
|
||||||
|
// -blendu on | off # set horizontal texture blending
|
||||||
|
// (default on)
|
||||||
|
// -blendv on | off # set vertical texture blending
|
||||||
|
// (default on)
|
||||||
|
// -boost float_value # boost mip-map sharpness
|
||||||
|
// -mm base_value gain_value # modify texture map values (default
|
||||||
|
// 0 1)
|
||||||
|
// # base_value = brightness,
|
||||||
|
// gain_value = contrast
|
||||||
|
// -o u [v [w]] # Origin offset (default
|
||||||
|
// 0 0 0)
|
||||||
|
// -s u [v [w]] # Scale (default
|
||||||
|
// 1 1 1)
|
||||||
|
// -t u [v [w]] # Turbulence (default
|
||||||
|
// 0 0 0)
|
||||||
|
// -texres resolution # texture resolution to create
|
||||||
|
// -clamp on | off # only render texels in the clamped
|
||||||
|
// 0-1 range (default off)
|
||||||
|
// # When unclamped, textures are
|
||||||
|
// repeated across a surface,
|
||||||
|
// # when clamped, only texels which
|
||||||
|
// fall within the 0-1
|
||||||
|
// # range are rendered.
|
||||||
|
// -bm mult_value # bump multiplier (for bump maps
|
||||||
|
// only)
|
||||||
|
//
|
||||||
|
// -imfchan r | g | b | m | l | z # specifies which channel of the file
|
||||||
|
// is used to
|
||||||
|
// # create a scalar or bump texture.
|
||||||
|
// r:red, g:green,
|
||||||
|
// # b:blue, m:matte, l:luminance,
|
||||||
|
// z:z-depth..
|
||||||
|
// # (the default for bump is 'l' and
|
||||||
|
// for decal is 'm')
|
||||||
|
// bump -imfchan r bumpmap.tga # says to use the red channel of
|
||||||
|
// bumpmap.tga as the bumpmap
|
||||||
|
//
|
||||||
|
// For reflection maps...
|
||||||
|
//
|
||||||
|
// -type sphere # specifies a sphere for a "refl"
|
||||||
|
// reflection map
|
||||||
|
// -type cube_top | cube_bottom | # when using a cube map, the texture
|
||||||
|
// file for each
|
||||||
|
// cube_front | cube_back | # side of the cube is specified
|
||||||
|
// separately
|
||||||
|
// cube_left | cube_right
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TEXTURE_TYPE_NONE, // default
|
||||||
|
TEXTURE_TYPE_SPHERE,
|
||||||
|
TEXTURE_TYPE_CUBE_TOP,
|
||||||
|
TEXTURE_TYPE_CUBE_BOTTOM,
|
||||||
|
TEXTURE_TYPE_CUBE_FRONT,
|
||||||
|
TEXTURE_TYPE_CUBE_BACK,
|
||||||
|
TEXTURE_TYPE_CUBE_LEFT,
|
||||||
|
TEXTURE_TYPE_CUBE_RIGHT
|
||||||
|
} texture_type_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
texture_type_t type; // -type (default TEXTURE_TYPE_NONE)
|
||||||
|
float sharpness; // -boost (default 1.0?)
|
||||||
|
float brightness; // base_value in -mm option (default 0)
|
||||||
|
float contrast; // gain_value in -mm option (default 1)
|
||||||
|
float origin_offset[3]; // -o u [v [w]] (default 0 0 0)
|
||||||
|
float scale[3]; // -s u [v [w]] (default 1 1 1)
|
||||||
|
float turbulence[3]; // -t u [v [w]] (default 0 0 0)
|
||||||
|
// int texture_resolution; // -texres resolution (default = ?) TODO
|
||||||
|
bool clamp; // -clamp (default false)
|
||||||
|
char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm')
|
||||||
|
bool blendu; // -blendu (default on)
|
||||||
|
bool blendv; // -blendv (default on)
|
||||||
|
float bump_multiplier; // -bm (for bump maps only, default 1.0)
|
||||||
|
} texture_option_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
@@ -66,21 +146,39 @@ typedef struct {
|
|||||||
std::string displacement_texname; // disp
|
std::string displacement_texname; // disp
|
||||||
std::string alpha_texname; // map_d
|
std::string alpha_texname; // map_d
|
||||||
|
|
||||||
|
texture_option_t ambient_texopt;
|
||||||
|
texture_option_t diffuse_texopt;
|
||||||
|
texture_option_t specular_texopt;
|
||||||
|
texture_option_t specular_highlight_texopt;
|
||||||
|
texture_option_t bump_texopt;
|
||||||
|
texture_option_t displacement_texopt;
|
||||||
|
texture_option_t alpha_texopt;
|
||||||
|
|
||||||
// PBR extension
|
// PBR extension
|
||||||
// http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
// http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
|
||||||
float roughness; // [0, 1] default 0
|
float roughness; // [0, 1] default 0
|
||||||
float metallic; // [0, 1] default 0
|
float metallic; // [0, 1] default 0
|
||||||
float sheen; // [0, 1] default 0
|
float sheen; // [0, 1] default 0
|
||||||
float clearcoat_thickness; // [0, 1] default 0
|
float clearcoat_thickness; // [0, 1] default 0
|
||||||
float clearcoat_roughness; // [0, 1] default 0
|
float clearcoat_roughness; // [0, 1] default 0
|
||||||
float anisotropy; // aniso. [0, 1] default 0
|
float anisotropy; // aniso. [0, 1] default 0
|
||||||
float anisotropy_rotation; // anisor. [0, 1] default 0
|
float anisotropy_rotation; // anisor. [0, 1] default 0
|
||||||
|
float pad0;
|
||||||
|
float pad1;
|
||||||
std::string roughness_texname; // map_Pr
|
std::string roughness_texname; // map_Pr
|
||||||
std::string metallic_texname; // map_Pm
|
std::string metallic_texname; // map_Pm
|
||||||
std::string sheen_texname; // map_Ps
|
std::string sheen_texname; // map_Ps
|
||||||
std::string emissive_texname; // map_Ke
|
std::string emissive_texname; // map_Ke
|
||||||
std::string normal_texname; // norm. For normal mapping.
|
std::string normal_texname; // norm. For normal mapping.
|
||||||
|
|
||||||
|
texture_option_t roughness_texopt;
|
||||||
|
texture_option_t metallic_texopt;
|
||||||
|
texture_option_t sheen_texopt;
|
||||||
|
texture_option_t emissive_texopt;
|
||||||
|
texture_option_t normal_texopt;
|
||||||
|
|
||||||
|
int pad2;
|
||||||
|
|
||||||
std::map<std::string, std::string> unknown_parameter;
|
std::map<std::string, std::string> unknown_parameter;
|
||||||
} material_t;
|
} material_t;
|
||||||
|
|
||||||
@@ -169,15 +267,15 @@ class MaterialReader {
|
|||||||
|
|
||||||
class MaterialFileReader : public MaterialReader {
|
class MaterialFileReader : public MaterialReader {
|
||||||
public:
|
public:
|
||||||
explicit MaterialFileReader(const std::string &mtl_basepath)
|
explicit MaterialFileReader(const std::string &mtl_basedir)
|
||||||
: m_mtlBasePath(mtl_basepath) {}
|
: m_mtlBaseDir(mtl_basedir) {}
|
||||||
virtual ~MaterialFileReader() {}
|
virtual ~MaterialFileReader() {}
|
||||||
virtual bool operator()(const std::string &matId,
|
virtual bool operator()(const std::string &matId,
|
||||||
std::vector<material_t> *materials,
|
std::vector<material_t> *materials,
|
||||||
std::map<std::string, int> *matMap, std::string *err);
|
std::map<std::string, int> *matMap, std::string *err);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_mtlBasePath;
|
std::string m_mtlBaseDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MaterialStreamReader : public MaterialReader {
|
class MaterialStreamReader : public MaterialReader {
|
||||||
@@ -198,12 +296,13 @@ class MaterialStreamReader : public MaterialReader {
|
|||||||
/// 'shapes' will be filled with parsed shape data
|
/// 'shapes' will be filled with parsed shape data
|
||||||
/// Returns true when loading .obj become success.
|
/// Returns true when loading .obj become success.
|
||||||
/// Returns warning and error message into `err`
|
/// Returns warning and error message into `err`
|
||||||
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
/// 'mtl_basedir' is optional, and used for base directory for .mtl file.
|
||||||
|
/// In default(`NULL'), .mtl file is searched from an application's working directory.
|
||||||
/// 'triangulate' is optional, and used whether triangulate polygon face in .obj
|
/// 'triangulate' is optional, and used whether triangulate polygon face in .obj
|
||||||
/// 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_basepath = NULL,
|
const char *filename, const char *mtl_basedir = 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.
|
||||||
@@ -418,8 +517,14 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
|
|||||||
read = 1;
|
read = 1;
|
||||||
end_not_reached = (curr != s_end);
|
end_not_reached = (curr != s_end);
|
||||||
while (end_not_reached && IS_DIGIT(*curr)) {
|
while (end_not_reached && IS_DIGIT(*curr)) {
|
||||||
|
static const double pow_lut[] = {
|
||||||
|
1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001,
|
||||||
|
};
|
||||||
|
const int lut_entries = sizeof pow_lut / sizeof pow_lut[0];
|
||||||
|
|
||||||
// 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) *
|
||||||
|
(read < lut_entries ? pow_lut[read] : pow(10.0, -read));
|
||||||
read++;
|
read++;
|
||||||
curr++;
|
curr++;
|
||||||
end_not_reached = (curr != s_end);
|
end_not_reached = (curr != s_end);
|
||||||
@@ -460,7 +565,8 @@ static bool tryParseDouble(const char *s, const char *s_end, double *result) {
|
|||||||
|
|
||||||
assemble:
|
assemble:
|
||||||
*result =
|
*result =
|
||||||
(sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent);
|
(sign == '+' ? 1 : -1) *
|
||||||
|
(exponent ? ldexp(mantissa * pow(5.0, exponent), exponent) : mantissa);
|
||||||
return true;
|
return true;
|
||||||
fail:
|
fail:
|
||||||
return false;
|
return false;
|
||||||
@@ -476,24 +582,72 @@ static inline float parseFloat(const char **token, double default_value = 0.0) {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void parseFloat2(float *x, float *y, const char **token) {
|
static inline void parseFloat2(float *x, float *y, const char **token,
|
||||||
(*x) = parseFloat(token);
|
const double default_x = 0.0,
|
||||||
(*y) = parseFloat(token);
|
const double default_y = 0.0) {
|
||||||
|
(*x) = parseFloat(token, default_x);
|
||||||
|
(*y) = parseFloat(token, default_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void parseFloat3(float *x, float *y, float *z,
|
static inline void parseFloat3(float *x, float *y, float *z, const char **token,
|
||||||
const char **token) {
|
const double default_x = 0.0,
|
||||||
(*x) = parseFloat(token);
|
const double default_y = 0.0,
|
||||||
(*y) = parseFloat(token);
|
const double default_z = 0.0) {
|
||||||
(*z) = parseFloat(token);
|
(*x) = parseFloat(token, default_x);
|
||||||
|
(*y) = parseFloat(token, default_y);
|
||||||
|
(*z) = parseFloat(token, default_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void parseV(float *x, float *y, float *z, float *w,
|
static inline void parseV(float *x, float *y, float *z, float *w,
|
||||||
const char **token) {
|
const char **token, const double default_x = 0.0,
|
||||||
(*x) = parseFloat(token);
|
const double default_y = 0.0,
|
||||||
(*y) = parseFloat(token);
|
const double default_z = 0.0,
|
||||||
(*z) = parseFloat(token);
|
const double default_w = 1.0) {
|
||||||
(*w) = parseFloat(token, 1.0);
|
(*x) = parseFloat(token, default_x);
|
||||||
|
(*y) = parseFloat(token, default_y);
|
||||||
|
(*z) = parseFloat(token, default_z);
|
||||||
|
(*w) = parseFloat(token, default_w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool parseOnOff(const char **token, bool default_value = true) {
|
||||||
|
(*token) += strspn((*token), " \t");
|
||||||
|
const char *end = (*token) + strcspn((*token), " \t\r");
|
||||||
|
|
||||||
|
bool ret = default_value;
|
||||||
|
if ((0 == strncmp((*token), "on", 2))) {
|
||||||
|
ret = true;
|
||||||
|
} else if ((0 == strncmp((*token), "off", 3))) {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*token) = end;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline texture_type_t parseTextureType(
|
||||||
|
const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) {
|
||||||
|
(*token) += strspn((*token), " \t");
|
||||||
|
const char *end = (*token) + strcspn((*token), " \t\r");
|
||||||
|
texture_type_t ty = default_value;
|
||||||
|
|
||||||
|
if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_TOP;
|
||||||
|
} else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_BOTTOM;
|
||||||
|
} else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_LEFT;
|
||||||
|
} else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_RIGHT;
|
||||||
|
} else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_FRONT;
|
||||||
|
} else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) {
|
||||||
|
ty = TEXTURE_TYPE_CUBE_BACK;
|
||||||
|
} else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) {
|
||||||
|
ty = TEXTURE_TYPE_SPHERE;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*token) = end;
|
||||||
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
static tag_sizes parseTagTriple(const char **token) {
|
static tag_sizes parseTagTriple(const char **token) {
|
||||||
@@ -586,6 +740,102 @@ static vertex_index parseRawTriple(const char **token) {
|
|||||||
return vi;
|
return vi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ParseTextureNameAndOption(std::string *texname,
|
||||||
|
texture_option_t *texopt,
|
||||||
|
const char *linebuf, const bool is_bump) {
|
||||||
|
// @todo { write more robust lexer and parser. }
|
||||||
|
bool found_texname = false;
|
||||||
|
std::string texture_name;
|
||||||
|
|
||||||
|
// Fill with default value for texopt.
|
||||||
|
if (is_bump) {
|
||||||
|
texopt->imfchan = 'l';
|
||||||
|
} else {
|
||||||
|
texopt->imfchan = 'm';
|
||||||
|
}
|
||||||
|
texopt->bump_multiplier = 1.0f;
|
||||||
|
texopt->clamp = false;
|
||||||
|
texopt->blendu = true;
|
||||||
|
texopt->blendv = true;
|
||||||
|
texopt->sharpness = 1.0f;
|
||||||
|
texopt->brightness = 0.0f;
|
||||||
|
texopt->contrast = 1.0f;
|
||||||
|
texopt->origin_offset[0] = 0.0f;
|
||||||
|
texopt->origin_offset[1] = 0.0f;
|
||||||
|
texopt->origin_offset[2] = 0.0f;
|
||||||
|
texopt->scale[0] = 1.0f;
|
||||||
|
texopt->scale[1] = 1.0f;
|
||||||
|
texopt->scale[2] = 1.0f;
|
||||||
|
texopt->turbulence[0] = 0.0f;
|
||||||
|
texopt->turbulence[1] = 0.0f;
|
||||||
|
texopt->turbulence[2] = 0.0f;
|
||||||
|
texopt->type = TEXTURE_TYPE_NONE;
|
||||||
|
|
||||||
|
const char *token = linebuf; // Assume line ends with NULL
|
||||||
|
|
||||||
|
while (!IS_NEW_LINE((*token))) {
|
||||||
|
if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) {
|
||||||
|
token += 8;
|
||||||
|
texopt->blendu = parseOnOff(&token, /* default */ true);
|
||||||
|
} else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) {
|
||||||
|
token += 8;
|
||||||
|
texopt->blendv = parseOnOff(&token, /* default */ true);
|
||||||
|
} else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) {
|
||||||
|
token += 7;
|
||||||
|
texopt->clamp = parseOnOff(&token, /* default */ true);
|
||||||
|
} else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) {
|
||||||
|
token += 7;
|
||||||
|
texopt->sharpness = parseFloat(&token, 1.0);
|
||||||
|
} else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) {
|
||||||
|
token += 4;
|
||||||
|
texopt->bump_multiplier = parseFloat(&token, 1.0);
|
||||||
|
} else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) {
|
||||||
|
token += 3;
|
||||||
|
parseFloat3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]),
|
||||||
|
&(texopt->origin_offset[2]), &token);
|
||||||
|
} else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) {
|
||||||
|
token += 3;
|
||||||
|
parseFloat3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]),
|
||||||
|
&token, 1.0, 1.0, 1.0);
|
||||||
|
} else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) {
|
||||||
|
token += 3;
|
||||||
|
parseFloat3(&(texopt->turbulence[0]), &(texopt->turbulence[1]),
|
||||||
|
&(texopt->turbulence[2]), &token);
|
||||||
|
} else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) {
|
||||||
|
token += 5;
|
||||||
|
texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE);
|
||||||
|
} else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) {
|
||||||
|
token += 9;
|
||||||
|
token += strspn(token, " \t");
|
||||||
|
const char *end = token + strcspn(token, " \t\r");
|
||||||
|
if ((end - token) == 1) { // Assume one char for -imfchan
|
||||||
|
texopt->imfchan = (*token);
|
||||||
|
}
|
||||||
|
token = end;
|
||||||
|
} else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) {
|
||||||
|
token += 4;
|
||||||
|
parseFloat2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
|
||||||
|
} else {
|
||||||
|
// Assume texture filename
|
||||||
|
token += strspn(token, " \t"); // skip space
|
||||||
|
size_t len = strcspn(token, " \t\r"); // untile next space
|
||||||
|
texture_name = std::string(token, token + len);
|
||||||
|
token += len;
|
||||||
|
|
||||||
|
token += strspn(token, " \t"); // skip space
|
||||||
|
|
||||||
|
found_texname = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_texname) {
|
||||||
|
(*texname) = texture_name;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void InitMaterial(material_t *material) {
|
static void InitMaterial(material_t *material) {
|
||||||
material->name = "";
|
material->name = "";
|
||||||
material->ambient_texname = "";
|
material->ambient_texname = "";
|
||||||
@@ -686,15 +936,26 @@ static bool exportFaceGroupToShape(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split a string with specified delimiter character.
|
||||||
|
// http://stackoverflow.com/questions/236129/split-a-string-in-c
|
||||||
|
static void SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.str(s);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
elems.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LoadMtl(std::map<std::string, int> *material_map,
|
void LoadMtl(std::map<std::string, int> *material_map,
|
||||||
std::vector<material_t> *materials, std::istream *inStream) {
|
std::vector<material_t> *materials, std::istream *inStream) {
|
||||||
// Create a default material anyway.
|
// Create a default material anyway.
|
||||||
material_t material;
|
material_t material;
|
||||||
InitMaterial(&material);
|
InitMaterial(&material);
|
||||||
|
|
||||||
|
std::string linebuf;
|
||||||
while (inStream->peek() != -1) {
|
while (inStream->peek() != -1) {
|
||||||
std::string linebuf;
|
|
||||||
|
|
||||||
safeGetline(*inStream, linebuf);
|
safeGetline(*inStream, linebuf);
|
||||||
|
|
||||||
// Trim trailing whitespace.
|
// Trim trailing whitespace.
|
||||||
@@ -892,35 +1153,54 @@ void LoadMtl(std::map<std::string, int> *material_map,
|
|||||||
// ambient texture
|
// ambient texture
|
||||||
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.ambient_texname = token;
|
ParseTextureNameAndOption(&(material.ambient_texname),
|
||||||
|
&(material.ambient_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// diffuse texture
|
// diffuse texture
|
||||||
if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.diffuse_texname = token;
|
ParseTextureNameAndOption(&(material.diffuse_texname),
|
||||||
|
&(material.diffuse_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// specular texture
|
// specular texture
|
||||||
if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.specular_texname = token;
|
ParseTextureNameAndOption(&(material.specular_texname),
|
||||||
|
&(material.specular_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// specular highlight texture
|
// specular highlight texture
|
||||||
if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.specular_highlight_texname = token;
|
ParseTextureNameAndOption(&(material.specular_highlight_texname),
|
||||||
|
&(material.specular_highlight_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bump texture
|
// bump texture
|
||||||
if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) {
|
if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) {
|
||||||
token += 9;
|
token += 9;
|
||||||
material.bump_texname = token;
|
ParseTextureNameAndOption(&(material.bump_texname),
|
||||||
|
&(material.bump_texopt), token,
|
||||||
|
/* is_bump */ true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bump texture
|
||||||
|
if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
|
||||||
|
token += 5;
|
||||||
|
ParseTextureNameAndOption(&(material.bump_texname),
|
||||||
|
&(material.bump_texopt), token,
|
||||||
|
/* is_bump */ true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,55 +1208,63 @@ void LoadMtl(std::map<std::string, int> *material_map,
|
|||||||
if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(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;
|
ParseTextureNameAndOption(&(material.alpha_texname),
|
||||||
}
|
&(material.alpha_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
// bump texture
|
|
||||||
if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
|
|
||||||
token += 5;
|
|
||||||
material.bump_texname = token;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// displacement texture
|
// displacement texture
|
||||||
if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
|
if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
|
||||||
token += 5;
|
token += 5;
|
||||||
material.displacement_texname = token;
|
ParseTextureNameAndOption(&(material.displacement_texname),
|
||||||
|
&(material.displacement_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PBR: roughness texture
|
// PBR: roughness texture
|
||||||
if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.roughness_texname = token;
|
ParseTextureNameAndOption(&(material.roughness_texname),
|
||||||
|
&(material.roughness_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PBR: metallic texture
|
// PBR: metallic texture
|
||||||
if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.metallic_texname = token;
|
ParseTextureNameAndOption(&(material.metallic_texname),
|
||||||
|
&(material.metallic_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PBR: sheen texture
|
// PBR: sheen texture
|
||||||
if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.sheen_texname = token;
|
ParseTextureNameAndOption(&(material.sheen_texname),
|
||||||
|
&(material.sheen_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PBR: emissive texture
|
// PBR: emissive texture
|
||||||
if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
|
if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
|
||||||
token += 7;
|
token += 7;
|
||||||
material.emissive_texname = token;
|
ParseTextureNameAndOption(&(material.emissive_texname),
|
||||||
|
&(material.emissive_texopt), token,
|
||||||
|
/* is_bump */ false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PBR: normal map texture
|
// PBR: normal map texture
|
||||||
if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
|
if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
|
||||||
token += 5;
|
token += 5;
|
||||||
material.normal_texname = token;
|
ParseTextureNameAndOption(
|
||||||
|
&(material.normal_texname), &(material.normal_texopt), token,
|
||||||
|
/* is_bump */ false); // @fixme { is_bump will be true? }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,22 +1293,24 @@ bool MaterialFileReader::operator()(const std::string &matId,
|
|||||||
std::string *err) {
|
std::string *err) {
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
|
||||||
if (!m_mtlBasePath.empty()) {
|
if (!m_mtlBaseDir.empty()) {
|
||||||
filepath = std::string(m_mtlBasePath) + matId;
|
filepath = std::string(m_mtlBaseDir) + matId;
|
||||||
} else {
|
} else {
|
||||||
filepath = matId;
|
filepath = matId;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ifstream matIStream(filepath.c_str());
|
std::ifstream matIStream(filepath.c_str());
|
||||||
LoadMtl(matMap, materials, &matIStream);
|
|
||||||
if (!matIStream) {
|
if (!matIStream) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "WARN: Material file [ " << filepath
|
ss << "WARN: Material file [ " << filepath
|
||||||
<< " ] not found. Created a default material.";
|
<< " ] not found." << std::endl;
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += ss.str();
|
(*err) += ss.str();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadMtl(matMap, materials, &matIStream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,21 +1318,23 @@ bool MaterialStreamReader::operator()(const std::string &matId,
|
|||||||
std::vector<material_t> *materials,
|
std::vector<material_t> *materials,
|
||||||
std::map<std::string, int> *matMap,
|
std::map<std::string, int> *matMap,
|
||||||
std::string *err) {
|
std::string *err) {
|
||||||
LoadMtl(matMap, materials, &m_inStream);
|
(void)matId;
|
||||||
if (!m_inStream) {
|
if (!m_inStream) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "WARN: Material stream in error state."
|
ss << "WARN: Material stream in error state. " << std::endl;
|
||||||
<< " Created a default material.";
|
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += ss.str();
|
(*err) += ss.str();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadMtl(matMap, materials, &m_inStream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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_basepath,
|
const char *filename, const char *mtl_basedir,
|
||||||
bool trianglulate) {
|
bool trianglulate) {
|
||||||
attrib->vertices.clear();
|
attrib->vertices.clear();
|
||||||
attrib->normals.clear();
|
attrib->normals.clear();
|
||||||
@@ -1060,11 +1352,11 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string basePath;
|
std::string baseDir;
|
||||||
if (mtl_basepath) {
|
if (mtl_basedir) {
|
||||||
basePath = mtl_basepath;
|
baseDir = mtl_basedir;
|
||||||
}
|
}
|
||||||
MaterialFileReader matFileReader(basePath);
|
MaterialFileReader matFileReader(baseDir);
|
||||||
|
|
||||||
return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader,
|
return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader,
|
||||||
trianglulate);
|
trianglulate);
|
||||||
@@ -1072,8 +1364,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
|
|
||||||
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,
|
std::istream *inStream, MaterialReader *readMatFn /*= NULL*/,
|
||||||
MaterialReader *readMatFn /*= NULL*/,
|
|
||||||
bool triangulate) {
|
bool triangulate) {
|
||||||
std::stringstream errss;
|
std::stringstream errss;
|
||||||
|
|
||||||
@@ -1090,8 +1381,8 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
|
|
||||||
shape_t shape;
|
shape_t shape;
|
||||||
|
|
||||||
|
std::string linebuf;
|
||||||
while (inStream->peek() != -1) {
|
while (inStream->peek() != -1) {
|
||||||
std::string linebuf;
|
|
||||||
safeGetline(*inStream, linebuf);
|
safeGetline(*inStream, linebuf);
|
||||||
|
|
||||||
// Trim newline '\r\n' or '\n'
|
// Trim newline '\r\n' or '\n'
|
||||||
@@ -1207,23 +1498,37 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
|||||||
// load mtl
|
// load mtl
|
||||||
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
||||||
if (readMatFn) {
|
if (readMatFn) {
|
||||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
|
||||||
token += 7;
|
token += 7;
|
||||||
#ifdef _MSC_VER
|
|
||||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
|
||||||
#else
|
|
||||||
sscanf(token, "%s", namebuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::string err_mtl;
|
std::vector<std::string> filenames;
|
||||||
bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl);
|
SplitString(std::string(token), ' ', filenames);
|
||||||
if (err) {
|
|
||||||
(*err) += err_mtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
if (filenames.empty()) {
|
||||||
faceGroup.clear(); // for safety
|
if (err) {
|
||||||
return false;
|
(*err) += "WARN: Looks like empty filename for mtllib. Use default material. \n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (size_t s = 0; s < filenames.size(); s++) {
|
||||||
|
|
||||||
|
std::string err_mtl;
|
||||||
|
bool ok = (*readMatFn)(filenames[s].c_str(), materials, &material_map, &err_mtl);
|
||||||
|
if (err && (!err_mtl.empty())) {
|
||||||
|
(*err) += err_mtl; // This should be warn message.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "WARN: Failed to load material file(s). Use default material.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1499,28 +1804,44 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
|||||||
// load mtl
|
// load mtl
|
||||||
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
|
||||||
if (readMatFn) {
|
if (readMatFn) {
|
||||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
|
||||||
token += 7;
|
token += 7;
|
||||||
#ifdef _MSC_VER
|
token += 7;
|
||||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
|
||||||
#else
|
|
||||||
sscanf(token, "%s", namebuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::string err_mtl;
|
std::vector<std::string> filenames;
|
||||||
materials.clear();
|
SplitString(std::string(token), ' ', filenames);
|
||||||
bool ok = (*readMatFn)(namebuf, &materials, &material_map, &err_mtl);
|
|
||||||
if (err) {
|
|
||||||
(*err) += err_mtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
if (filenames.empty()) {
|
||||||
return false;
|
if (err) {
|
||||||
}
|
(*err) += "WARN: Looks like empty filename for mtllib. Use default material. \n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
if (callback.mtllib_cb) {
|
bool found = false;
|
||||||
callback.mtllib_cb(user_data, &materials.at(0),
|
for (size_t s = 0; s < filenames.size(); s++) {
|
||||||
static_cast<int>(materials.size()));
|
|
||||||
|
std::string err_mtl;
|
||||||
|
bool ok = (*readMatFn)(filenames[s].c_str(), &materials, &material_map, &err_mtl);
|
||||||
|
if (err && (!err_mtl.empty())) {
|
||||||
|
(*err) += err_mtl; // This should be warn message.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
if (err) {
|
||||||
|
(*err) += "WARN: Failed to load material file(s). Use default material.\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (callback.mtllib_cb) {
|
||||||
|
callback.mtllib_cb(user_data, &materials.at(0),
|
||||||
|
static_cast<int>(materials.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user