Merge branch 'master' of github.com:syoyo/tinyobjloader
This commit is contained in:
6755
examples/viewer/stb_image.h
Normal file
6755
examples/viewer/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -26,12 +27,24 @@
|
|||||||
|
|
||||||
#include "trackball.h"
|
#include "trackball.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#include <mmsystem.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mmsystem.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -112,6 +125,7 @@ class timerutil {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
GLuint vb; // vertex buffer
|
GLuint vb; // vertex buffer
|
||||||
int numTriangles;
|
int numTriangles;
|
||||||
|
size_t material_id;
|
||||||
} DrawObject;
|
} DrawObject;
|
||||||
|
|
||||||
std::vector<DrawObject> gDrawObjects;
|
std::vector<DrawObject> gDrawObjects;
|
||||||
@@ -163,10 +177,11 @@ void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
|
|||||||
|
|
||||||
bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
||||||
std::vector<DrawObject>* drawObjects,
|
std::vector<DrawObject>* drawObjects,
|
||||||
|
std::vector<tinyobj::material_t>& materials,
|
||||||
|
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;
|
||||||
std::vector<tinyobj::material_t> materials;
|
|
||||||
|
|
||||||
timerutil tm;
|
timerutil tm;
|
||||||
|
|
||||||
@@ -194,17 +209,82 @@ 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());
|
||||||
|
|
||||||
|
// Load diffuse textures
|
||||||
|
{
|
||||||
|
for (size_t m = 0; m < materials.size(); 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;
|
||||||
|
unsigned char* image = stbi_load(mp->diffuse_texname.c_str(), &w, &h, &comp, STBI_default);
|
||||||
|
if (image == nullptr) {
|
||||||
|
std::cerr << "Unable to load texture: " << mp->diffuse_texname << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
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_NEAREST);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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();
|
||||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||||
|
|
||||||
{
|
{
|
||||||
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++) {
|
||||||
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];
|
||||||
|
|
||||||
|
current_material_id = shapes[s].mesh.material_ids[f];
|
||||||
|
|
||||||
|
if (current_material_id >= materials.size()) {
|
||||||
|
std::cerr << "Invalid material index: " << current_material_id << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diffuse[3];
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
diffuse[i] = materials[current_material_id].diffuse[i];
|
||||||
|
}
|
||||||
|
float tc[3][2];
|
||||||
|
if (attrib.texcoords.size() > 0) {
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1);
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1);
|
||||||
|
assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1);
|
||||||
|
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
|
||||||
|
tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
|
||||||
|
tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
|
||||||
|
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
|
||||||
|
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
|
||||||
|
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
|
||||||
|
} else {
|
||||||
|
std::cerr << "Texcoordinates are not defined" << std::endl;
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
float v[3][3];
|
float v[3][3];
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
@@ -227,7 +307,6 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
}
|
}
|
||||||
|
|
||||||
float n[3][3];
|
float n[3][3];
|
||||||
|
|
||||||
if (attrib.normals.size() > 0) {
|
if (attrib.normals.size() > 0) {
|
||||||
int f0 = idx0.normal_index;
|
int f0 = idx0.normal_index;
|
||||||
int f1 = idx1.normal_index;
|
int f1 = idx1.normal_index;
|
||||||
@@ -258,8 +337,14 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
vb.push_back(n[k][0]);
|
vb.push_back(n[k][0]);
|
||||||
vb.push_back(n[k][1]);
|
vb.push_back(n[k][1]);
|
||||||
vb.push_back(n[k][2]);
|
vb.push_back(n[k][2]);
|
||||||
// Use normal as color.
|
// Combine normal and diffuse to get color.
|
||||||
float c[3] = {n[k][0], n[k][1], n[k][2]};
|
float normal_factor = 0.2;
|
||||||
|
float diffuse_factor = 1 - normal_factor;
|
||||||
|
float c[3] = {
|
||||||
|
n[k][0] * normal_factor + diffuse[0] * 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);
|
||||||
@@ -271,17 +356,21 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3],
|
|||||||
vb.push_back(c[0] * 0.5 + 0.5);
|
vb.push_back(c[0] * 0.5 + 0.5);
|
||||||
vb.push_back(c[1] * 0.5 + 0.5);
|
vb.push_back(c[1] * 0.5 + 0.5);
|
||||||
vb.push_back(c[2] * 0.5 + 0.5);
|
vb.push_back(c[2] * 0.5 + 0.5);
|
||||||
|
|
||||||
|
vb.push_back(tc[k][0]);
|
||||||
|
vb.push_back(tc[k][1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.vb = 0;
|
o.vb = 0;
|
||||||
o.numTriangles = 0;
|
o.numTriangles = 0;
|
||||||
|
o.material_id = current_material_id;
|
||||||
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);
|
||||||
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
|
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
|
||||||
GL_STATIC_DRAW);
|
GL_STATIC_DRAW);
|
||||||
o.numTriangles = vb.size() / 9 / 3;
|
o.numTriangles = vb.size() / (3 + 3 + 3 + 2) * 3;
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -395,13 +484,13 @@ void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
|
|||||||
prevMouseY = mouse_y;
|
prevMouseY = mouse_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(const std::vector<DrawObject>& drawObjects) {
|
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);
|
||||||
|
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(1.0, 1.0);
|
glPolygonOffset(1.0, 1.0);
|
||||||
glColor3f(1.0f, 1.0f, 1.0f);
|
GLsizei stride = (3 + 3 + 3 + 2) * sizeof(float);
|
||||||
for (size_t i = 0; i < drawObjects.size(); i++) {
|
for (size_t i = 0; i < drawObjects.size(); i++) {
|
||||||
DrawObject o = drawObjects[i];
|
DrawObject o = drawObjects[i];
|
||||||
if (o.vb < 1) {
|
if (o.vb < 1) {
|
||||||
@@ -412,12 +501,20 @@ void Draw(const std::vector<DrawObject>& drawObjects) {
|
|||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
|
||||||
glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float) * 6));
|
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
|
||||||
|
if (diffuse_texname.length() > 0) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
|
||||||
|
}
|
||||||
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
|
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||||
|
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||||
CheckErrors("drawarrays");
|
CheckErrors("drawarrays");
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw wireframe
|
// draw wireframe
|
||||||
@@ -436,8 +533,11 @@ void Draw(const std::vector<DrawObject>& drawObjects) {
|
|||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float) * 3));
|
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
|
||||||
|
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
|
||||||
|
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
|
||||||
CheckErrors("drawarrays");
|
CheckErrors("drawarrays");
|
||||||
@@ -498,7 +598,9 @@ int main(int argc, char** argv) {
|
|||||||
reshapeFunc(window, width, height);
|
reshapeFunc(window, width, height);
|
||||||
|
|
||||||
float bmin[3], bmax[3];
|
float bmin[3], bmax[3];
|
||||||
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, argv[1])) {
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
std::map<std::string, GLuint> textures;
|
||||||
|
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,6 +618,7 @@ int main(int argc, char** argv) {
|
|||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
// camera & rotate
|
// camera & rotate
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
@@ -533,7 +636,7 @@ int main(int argc, char** argv) {
|
|||||||
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
|
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
|
||||||
-0.5 * (bmax[2] + bmin[2]));
|
-0.5 * (bmax[2] + bmin[2]));
|
||||||
|
|
||||||
Draw(gDrawObjects);
|
Draw(gDrawObjects, materials, textures);
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,48 @@ TestLoadObj(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
TestLoadObjFromPreopenedFile(
|
||||||
|
const char* filename,
|
||||||
|
const char* basepath = NULL,
|
||||||
|
bool readMaterials = true,
|
||||||
|
bool triangulate = true)
|
||||||
|
{
|
||||||
|
std::string fullFilename = std::string(basepath) + filename;
|
||||||
|
std::cout << "Loading " << fullFilename << std::endl;
|
||||||
|
|
||||||
|
std::ifstream fileStream(fullFilename.c_str());
|
||||||
|
|
||||||
|
if (!fileStream) {
|
||||||
|
std::cerr << "Could not find specified file: " << fullFilename << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tinyobj::MaterialStreamReader materialStreamReader(fileStream);
|
||||||
|
tinyobj::MaterialStreamReader* materialReader = readMaterials
|
||||||
|
? &materialStreamReader
|
||||||
|
: NULL;
|
||||||
|
|
||||||
|
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, &fileStream, materialReader);
|
||||||
|
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
printf("Failed to load/parse .obj.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loaded material count: " << materials.size() << "\n";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
TestStreamLoadObj()
|
TestStreamLoadObj()
|
||||||
@@ -351,6 +393,16 @@ TEST_CASE("stream_load", "[Stream]") {
|
|||||||
REQUIRE(true == TestStreamLoadObj());
|
REQUIRE(true == TestStreamLoadObj());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("stream_load_from_file_skipping_materials", "[Stream]") {
|
||||||
|
REQUIRE(true == TestLoadObjFromPreopenedFile(
|
||||||
|
"../models/pbr-mat-ext.obj", gMtlBasePath, /*readMaterials*/false, /*triangulate*/false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("stream_load_from_file_with_materials", "[Stream]") {
|
||||||
|
REQUIRE(true == TestLoadObjFromPreopenedFile(
|
||||||
|
"../models/pbr-mat-ext.obj", gMtlBasePath, /*readMaterials*/true, /*triangulate*/false));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("trailing_whitespace_in_mtl", "[Issue92]") {
|
TEST_CASE("trailing_whitespace_in_mtl", "[Issue92]") {
|
||||||
tinyobj::attrib_t attrib;
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ typedef struct {
|
|||||||
std::vector<std::string> stringValues;
|
std::vector<std::string> stringValues;
|
||||||
} tag_t;
|
} tag_t;
|
||||||
|
|
||||||
// Index struct to support differnt indices for vtx/normal/texcoord.
|
// Index struct to support different indices for vtx/normal/texcoord.
|
||||||
// -1 means not used.
|
// -1 means not used.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int vertex_index;
|
int vertex_index;
|
||||||
@@ -180,6 +180,19 @@ class MaterialFileReader : public MaterialReader {
|
|||||||
std::string m_mtlBasePath;
|
std::string m_mtlBasePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MaterialStreamReader : public MaterialReader {
|
||||||
|
public:
|
||||||
|
explicit MaterialStreamReader(std::istream &inStream)
|
||||||
|
: m_inStream(inStream) {}
|
||||||
|
virtual ~MaterialStreamReader() {}
|
||||||
|
virtual bool operator()(const std::string &matId,
|
||||||
|
std::vector<material_t> *materials,
|
||||||
|
std::map<std::string, int> *matMap, std::string *err);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::istream &m_inStream;
|
||||||
|
};
|
||||||
|
|
||||||
/// Loads .obj from a file.
|
/// Loads .obj from a file.
|
||||||
/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data
|
/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data
|
||||||
/// 'shapes' will be filled with parsed shape data
|
/// 'shapes' will be filled with parsed shape data
|
||||||
@@ -210,7 +223,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,
|
std::istream *inStream, MaterialReader *readMatFn = NULL,
|
||||||
bool triangulate = true);
|
bool triangulate = true);
|
||||||
|
|
||||||
/// Loads materials into std::map
|
/// Loads materials into std::map
|
||||||
@@ -1011,6 +1024,22 @@ bool MaterialFileReader::operator()(const std::string &matId,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MaterialStreamReader::operator()(const std::string &matId,
|
||||||
|
std::vector<material_t> *materials,
|
||||||
|
std::map<std::string, int> *matMap,
|
||||||
|
std::string *err) {
|
||||||
|
LoadMtl(matMap, materials, &m_inStream);
|
||||||
|
if (!m_inStream) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "WARN: Material stream in error state."
|
||||||
|
<< " Created a default material.";
|
||||||
|
if (err) {
|
||||||
|
(*err) += ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_basepath,
|
||||||
@@ -1043,7 +1072,8 @@ 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, MaterialReader *readMatFn,
|
std::istream *inStream,
|
||||||
|
MaterialReader *readMatFn /*= NULL*/,
|
||||||
bool triangulate) {
|
bool triangulate) {
|
||||||
std::stringstream errss;
|
std::stringstream errss;
|
||||||
|
|
||||||
@@ -1176,23 +1206,25 @@ 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]))) {
|
||||||
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
if (readMatFn) {
|
||||||
token += 7;
|
char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
|
||||||
|
token += 7;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
|
||||||
#else
|
#else
|
||||||
sscanf(token, "%s", namebuf);
|
sscanf(token, "%s", namebuf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string err_mtl;
|
std::string err_mtl;
|
||||||
bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl);
|
bool ok = (*readMatFn)(namebuf, materials, &material_map, &err_mtl);
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += err_mtl;
|
(*err) += err_mtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
faceGroup.clear(); // for safety
|
faceGroup.clear(); // for safety
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user