Refactor and re-design tinyobjloader.
* Separete attribs(vtx,normal,texcoords) and shape. * Support different index for vtx/normal/texcoord.
This commit is contained in:
@@ -21,6 +21,7 @@ Tiny but powerful single file wavefront obj loader written in C++. No dependency
|
|||||||
What's new
|
What's new
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* XX YY, ZZZZ : New data strcutre and API!
|
||||||
* Jan 29, 2016 : Support n-polygon(no triangulation) and OpenSubdiv crease tag! Thanks dboogert!
|
* Jan 29, 2016 : Support n-polygon(no triangulation) and OpenSubdiv crease tag! Thanks dboogert!
|
||||||
* Nov 26, 2015 : Now single-header only!.
|
* Nov 26, 2015 : Now single-header only!.
|
||||||
* Nov 08, 2015 : Improved API.
|
* Nov 08, 2015 : Improved API.
|
||||||
|
|||||||
74
test.cc
74
test.cc
@@ -8,11 +8,35 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool triangulate = true)
|
static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool triangulate = true)
|
||||||
{
|
{
|
||||||
|
std::cout << "# of positions : " << (attrib.positions.size() / 3) << std::endl;
|
||||||
|
std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
|
||||||
|
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2) << std::endl;
|
||||||
|
|
||||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||||
std::cout << "# of materials : " << materials.size() << std::endl;
|
std::cout << "# of materials : " << materials.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t v = 0; v < attrib.positions.size() / 3; v++) {
|
||||||
|
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||||
|
static_cast<const double>(attrib.positions[3*v+0]),
|
||||||
|
static_cast<const double>(attrib.positions[3*v+1]),
|
||||||
|
static_cast<const double>(attrib.positions[3*v+2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
|
||||||
|
printf(" n[%ld] = (%f, %f, %f)\n", v,
|
||||||
|
static_cast<const double>(attrib.normals[3*v+0]),
|
||||||
|
static_cast<const double>(attrib.normals[3*v+1]),
|
||||||
|
static_cast<const double>(attrib.normals[3*v+2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
|
||||||
|
printf(" uv[%ld] = (%f, %f)\n", v,
|
||||||
|
static_cast<const double>(attrib.texcoords[2*v+0]),
|
||||||
|
static_cast<const double>(attrib.texcoords[2*v+1]));
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < shapes.size(); i++) {
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
||||||
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
||||||
@@ -22,11 +46,19 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::ve
|
|||||||
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
||||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||||
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
|
tinyobj::index_t i0 = shapes[i].mesh.indices[3*f+0];
|
||||||
|
tinyobj::index_t i1 = shapes[i].mesh.indices[3*f+1];
|
||||||
|
tinyobj::index_t i2 = shapes[i].mesh.indices[3*f+2];
|
||||||
|
printf(" idx[%ld] = %d/%d/%d, %d/%d/%d, %d/%d/%d. mat_id = %d\n", f,
|
||||||
|
i0.vertex_index, i0.normal_index, i0.texcoord_index,
|
||||||
|
i1.vertex_index, i1.normal_index, i1.texcoord_index,
|
||||||
|
i2.vertex_index, i2.normal_index, i2.texcoord_index,
|
||||||
|
shapes[i].mesh.material_ids[f]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
|
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
|
||||||
printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]);
|
tinyobj::index_t idx = shapes[i].mesh.indices[f];
|
||||||
|
printf(" idx[%ld] = %d/%d/%d\n", f, idx.vertex_index, idx.normal_index, idx.texcoord_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
|
||||||
@@ -44,14 +76,14 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::ve
|
|||||||
static_cast<long>(shapes[i].mesh.num_vertices[v]));
|
static_cast<long>(shapes[i].mesh.num_vertices[v]));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
//printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
||||||
assert((shapes[i].mesh.positions.size() % 3) == 0);
|
//assert((shapes[i].mesh.positions.size() % 3) == 0);
|
||||||
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
//for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
||||||
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
// printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||||
shapes[i].mesh.positions[3*v+0],
|
// static_cast<const double>(shapes[i].mesh.positions[3*v+0]),
|
||||||
shapes[i].mesh.positions[3*v+1],
|
// static_cast<const double>(shapes[i].mesh.positions[3*v+1]),
|
||||||
shapes[i].mesh.positions[3*v+2]);
|
// static_cast<const double>(shapes[i].mesh.positions[3*v+2]));
|
||||||
}
|
//}
|
||||||
|
|
||||||
printf("shape[%ld].num_tags: %ld\n", i, shapes[i].mesh.tags.size());
|
printf("shape[%ld].num_tags: %ld\n", i, shapes[i].mesh.tags.size());
|
||||||
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
|
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
|
||||||
@@ -70,7 +102,7 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::ve
|
|||||||
printf(" floats: [");
|
printf(" floats: [");
|
||||||
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j)
|
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j)
|
||||||
{
|
{
|
||||||
printf("%f", shapes[i].mesh.tags[t].floatValues[j]);
|
printf("%f", static_cast<const double>(shapes[i].mesh.tags[t].floatValues[j]));
|
||||||
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1))
|
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1))
|
||||||
{
|
{
|
||||||
printf(", ");
|
printf(", ");
|
||||||
@@ -128,11 +160,12 @@ TestLoadObj(
|
|||||||
{
|
{
|
||||||
std::cout << "Loading " << filename << std::endl;
|
std::cout << "Loading " << filename << std::endl;
|
||||||
|
|
||||||
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
std::vector<tinyobj::material_t> materials;
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
bool ret = tinyobj::LoadObj(shapes, materials, err, filename, basepath, triangulate);
|
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, basepath, triangulate);
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
@@ -143,7 +176,7 @@ TestLoadObj(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintInfo(shapes, materials, triangulate);
|
PrintInfo(attrib, shapes, materials, triangulate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -223,13 +256,13 @@ std::string matStream(
|
|||||||
virtual ~MaterialStringStreamReader() {}
|
virtual ~MaterialStringStreamReader() {}
|
||||||
virtual bool operator() (
|
virtual bool operator() (
|
||||||
const std::string& matId,
|
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)
|
||||||
{
|
{
|
||||||
(void)matId;
|
(void)matId;
|
||||||
(void)err;
|
(void)err;
|
||||||
LoadMtl(matMap, materials, m_matSStream);
|
LoadMtl(matMap, materials, &m_matSStream);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,10 +271,11 @@ std::string matStream(
|
|||||||
};
|
};
|
||||||
|
|
||||||
MaterialStringStreamReader matSSReader(matStream);
|
MaterialStringStreamReader matSSReader(matStream);
|
||||||
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
std::vector<tinyobj::material_t> materials;
|
std::vector<tinyobj::material_t> materials;
|
||||||
std::string err;
|
std::string err;
|
||||||
bool ret = tinyobj::LoadObj(shapes, materials, err, objStream, matSSReader);
|
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &objStream, &matSSReader);
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
@@ -251,7 +285,7 @@ std::string matStream(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintInfo(shapes, materials);
|
PrintInfo(attrib, shapes, materials);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
//
|
//
|
||||||
// Copyright 2012-2015, Syoyo Fujita.
|
// Copyright 2012-2016, Syoyo Fujita.
|
||||||
//
|
//
|
||||||
// Licensed under 2-clause BSD license.
|
// Licensed under 2-clause BSD license.
|
||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// version devel : Change data structure. Support different index for vertex/normal/texcoord(#73, #39)
|
||||||
// version 0.9.20: Fixes creating per-face material using `usemtl`(#68)
|
// version 0.9.20: Fixes creating per-face material using `usemtl`(#68)
|
||||||
// version 0.9.17: Support n-polygon and crease tag(OpenSubdiv extension)
|
// version 0.9.17: Support n-polygon and crease tag(OpenSubdiv extension)
|
||||||
// version 0.9.16: Make tinyobjloader header-only
|
// version 0.9.16: Make tinyobjloader header-only
|
||||||
@@ -81,11 +82,16 @@ 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.
|
||||||
|
// -1 means not used.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
std::vector<float> positions;
|
int vertex_index;
|
||||||
std::vector<float> normals;
|
int normal_index;
|
||||||
std::vector<float> texcoords;
|
int texcoord_index;
|
||||||
std::vector<unsigned int> indices;
|
} index_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::vector<index_t> indices;
|
||||||
std::vector<unsigned char>
|
std::vector<unsigned char>
|
||||||
num_vertices; // The number of vertices per face. Up to 255.
|
num_vertices; // The number of vertices per face. Up to 255.
|
||||||
std::vector<int> material_ids; // per-face material ID
|
std::vector<int> material_ids; // per-face material ID
|
||||||
@@ -97,15 +103,21 @@ typedef struct {
|
|||||||
mesh_t mesh;
|
mesh_t mesh;
|
||||||
} shape_t;
|
} shape_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::vector<float> positions;
|
||||||
|
std::vector<float> normals;
|
||||||
|
std::vector<float> texcoords;
|
||||||
|
} attrib_t;
|
||||||
|
|
||||||
class MaterialReader {
|
class MaterialReader {
|
||||||
public:
|
public:
|
||||||
MaterialReader() {}
|
MaterialReader() {}
|
||||||
virtual ~MaterialReader();
|
virtual ~MaterialReader();
|
||||||
|
|
||||||
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::map<std::string, int> *matMap,
|
||||||
std::string &err) = 0;
|
std::string *err) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MaterialFileReader : public MaterialReader {
|
class MaterialFileReader : public MaterialReader {
|
||||||
@@ -114,14 +126,15 @@ public:
|
|||||||
: m_mtlBasePath(mtl_basepath) {}
|
: m_mtlBasePath(mtl_basepath) {}
|
||||||
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_mtlBasePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Loads .obj from a file.
|
/// Loads .obj from a file.
|
||||||
|
/// '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
|
||||||
/// The function returns error string.
|
/// The function returns error string.
|
||||||
/// Returns true when loading .obj become success.
|
/// Returns true when loading .obj become success.
|
||||||
@@ -129,9 +142,10 @@ private:
|
|||||||
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
||||||
/// '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(std::vector<shape_t> &shapes, // [output]
|
bool LoadObj(attrib_t *attrib,
|
||||||
std::vector<material_t> &materials, // [output]
|
std::vector<shape_t> *shapes,
|
||||||
std::string &err, // [output]
|
std::vector<material_t> *materials,
|
||||||
|
std::string *err,
|
||||||
const char *filename, const char *mtl_basepath = NULL,
|
const char *filename, const char *mtl_basepath = NULL,
|
||||||
bool triangulate = true);
|
bool triangulate = true);
|
||||||
|
|
||||||
@@ -139,16 +153,17 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
/// std::istream for materials.
|
/// std::istream for materials.
|
||||||
/// 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`
|
||||||
bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
bool LoadObj(attrib_t *attrib,
|
||||||
std::vector<material_t> &materials, // [output]
|
std::vector<shape_t> *shapes,
|
||||||
std::string &err, // [output]
|
std::vector<material_t> *materials,
|
||||||
std::istream &inStream, MaterialReader &readMatFn,
|
std::string *err,
|
||||||
|
std::istream *inStream, MaterialReader *readMatFn,
|
||||||
bool triangulate = true);
|
bool triangulate = true);
|
||||||
|
|
||||||
/// Loads materials into std::map
|
/// Loads materials into std::map
|
||||||
void LoadMtl(std::map<std::string, int> &material_map, // [output]
|
void LoadMtl(std::map<std::string, int> *material_map,
|
||||||
std::vector<material_t> &materials, // [output]
|
std::vector<material_t> *materials,
|
||||||
std::istream &inStream);
|
std::istream *inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TINYOBJLOADER_IMPLEMENTATION
|
#ifdef TINYOBJLOADER_IMPLEMENTATION
|
||||||
@@ -204,7 +219,7 @@ struct obj_shape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define IS_SPACE( x ) ( ( (x) == ' ') || ( (x) == '\t') )
|
#define IS_SPACE( x ) ( ( (x) == ' ') || ( (x) == '\t') )
|
||||||
#define IS_DIGIT( x ) ( (unsigned int)( (x) - '0' ) < (unsigned int)10 )
|
#define IS_DIGIT( x ) ( static_cast<unsigned int>( (x) - '0' ) < static_cast<unsigned int>(10) )
|
||||||
#define IS_NEW_LINE( x ) ( ( (x) == '\r') || ( (x) == '\n') || ( (x) == '\0') )
|
#define IS_NEW_LINE( x ) ( ( (x) == '\r') || ( (x) == '\n') || ( (x) == '\0') )
|
||||||
|
|
||||||
// Make index zero-base, and also support relative index.
|
// Make index zero-base, and also support relative index.
|
||||||
@@ -447,45 +462,6 @@ static vertex_index parseTriple(const char *&token, int vsize, int vnsize,
|
|||||||
return vi;
|
return vi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
updateVertex(std::map<vertex_index, unsigned int> &vertexCache,
|
|
||||||
std::vector<float> &positions, std::vector<float> &normals,
|
|
||||||
std::vector<float> &texcoords,
|
|
||||||
const std::vector<float> &in_positions,
|
|
||||||
const std::vector<float> &in_normals,
|
|
||||||
const std::vector<float> &in_texcoords, const vertex_index &i) {
|
|
||||||
const std::map<vertex_index, unsigned int>::iterator it = vertexCache.find(i);
|
|
||||||
|
|
||||||
if (it != vertexCache.end()) {
|
|
||||||
// found cache
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(in_positions.size() > static_cast<unsigned int>(3 * i.v_idx + 2));
|
|
||||||
|
|
||||||
positions.push_back(in_positions[3 * static_cast<size_t>(i.v_idx) + 0]);
|
|
||||||
positions.push_back(in_positions[3 * static_cast<size_t>(i.v_idx) + 1]);
|
|
||||||
positions.push_back(in_positions[3 * static_cast<size_t>(i.v_idx) + 2]);
|
|
||||||
|
|
||||||
if ((i.vn_idx >= 0) &&
|
|
||||||
(static_cast<size_t>(i.vn_idx * 3 + 2) < in_normals.size())) {
|
|
||||||
normals.push_back(in_normals[3 * static_cast<size_t>(i.vn_idx) + 0]);
|
|
||||||
normals.push_back(in_normals[3 * static_cast<size_t>(i.vn_idx) + 1]);
|
|
||||||
normals.push_back(in_normals[3 * static_cast<size_t>(i.vn_idx) + 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((i.vt_idx >= 0) &&
|
|
||||||
(static_cast<size_t>(i.vt_idx * 2 + 1) < in_texcoords.size())) {
|
|
||||||
texcoords.push_back(in_texcoords[2 * static_cast<size_t>(i.vt_idx) + 0]);
|
|
||||||
texcoords.push_back(in_texcoords[2 * static_cast<size_t>(i.vt_idx) + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int idx = static_cast<unsigned int>(positions.size() / 3 - 1);
|
|
||||||
vertexCache[i] = idx;
|
|
||||||
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitMaterial(material_t &material) {
|
static void InitMaterial(material_t &material) {
|
||||||
material.name = "";
|
material.name = "";
|
||||||
material.ambient_texname = "";
|
material.ambient_texname = "";
|
||||||
@@ -510,13 +486,13 @@ static void InitMaterial(material_t &material) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool exportFaceGroupToShape(
|
static bool exportFaceGroupToShape(
|
||||||
shape_t &shape, std::map<vertex_index, unsigned int> vertexCache,
|
shape_t &shape,
|
||||||
const std::vector<float> &in_positions,
|
const std::vector<float> &in_positions,
|
||||||
const std::vector<float> &in_normals,
|
const std::vector<float> &in_normals,
|
||||||
const std::vector<float> &in_texcoords,
|
const std::vector<float> &in_texcoords,
|
||||||
const std::vector<std::vector<vertex_index> > &faceGroup,
|
const std::vector<std::vector<vertex_index> > &faceGroup,
|
||||||
std::vector<tag_t> &tags, const int material_id, const std::string &name,
|
std::vector<tag_t> &tags, const int material_id, const std::string &name,
|
||||||
bool clearCache, bool triangulate) {
|
bool triangulate) {
|
||||||
if (faceGroup.empty()) {
|
if (faceGroup.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -538,19 +514,20 @@ static bool exportFaceGroupToShape(
|
|||||||
i1 = i2;
|
i1 = i2;
|
||||||
i2 = face[k];
|
i2 = face[k];
|
||||||
|
|
||||||
unsigned int v0 = updateVertex(
|
index_t idx0, idx1, idx2;
|
||||||
vertexCache, shape.mesh.positions, shape.mesh.normals,
|
idx0.vertex_index = i0.v_idx;
|
||||||
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0);
|
idx0.normal_index = i0.vn_idx;
|
||||||
unsigned int v1 = updateVertex(
|
idx0.texcoord_index = i0.vt_idx;
|
||||||
vertexCache, shape.mesh.positions, shape.mesh.normals,
|
idx1.vertex_index = i1.v_idx;
|
||||||
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1);
|
idx1.normal_index = i1.vn_idx;
|
||||||
unsigned int v2 = updateVertex(
|
idx1.texcoord_index = i1.vt_idx;
|
||||||
vertexCache, shape.mesh.positions, shape.mesh.normals,
|
idx2.vertex_index = i2.v_idx;
|
||||||
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2);
|
idx2.normal_index = i2.vn_idx;
|
||||||
|
idx2.texcoord_index = i2.vt_idx;
|
||||||
|
|
||||||
shape.mesh.indices.push_back(v0);
|
shape.mesh.indices.push_back(idx0);
|
||||||
shape.mesh.indices.push_back(v1);
|
shape.mesh.indices.push_back(idx1);
|
||||||
shape.mesh.indices.push_back(v2);
|
shape.mesh.indices.push_back(idx2);
|
||||||
|
|
||||||
shape.mesh.num_vertices.push_back(3);
|
shape.mesh.num_vertices.push_back(3);
|
||||||
shape.mesh.material_ids.push_back(material_id);
|
shape.mesh.material_ids.push_back(material_id);
|
||||||
@@ -558,12 +535,10 @@ static bool exportFaceGroupToShape(
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (size_t k = 0; k < npolys; k++) {
|
for (size_t k = 0; k < npolys; k++) {
|
||||||
unsigned int v =
|
index_t idx;
|
||||||
updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals,
|
idx.vertex_index = face[k].v_idx;
|
||||||
shape.mesh.texcoords, in_positions, in_normals,
|
idx.normal_index = face[k].vn_idx;
|
||||||
in_texcoords, face[k]);
|
idx.texcoord_index = face[k].vt_idx;
|
||||||
|
|
||||||
shape.mesh.indices.push_back(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shape.mesh.num_vertices.push_back(static_cast<unsigned char>(npolys));
|
shape.mesh.num_vertices.push_back(static_cast<unsigned char>(npolys));
|
||||||
@@ -574,14 +549,11 @@ static bool exportFaceGroupToShape(
|
|||||||
shape.name = name;
|
shape.name = name;
|
||||||
shape.mesh.tags.swap(tags);
|
shape.mesh.tags.swap(tags);
|
||||||
|
|
||||||
if (clearCache)
|
|
||||||
vertexCache.clear();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -589,8 +561,8 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
|
|
||||||
size_t maxchars = 8192; // Alloc enough size.
|
size_t maxchars = 8192; // Alloc enough size.
|
||||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||||
while (inStream.peek() != -1) {
|
while (inStream->peek() != -1) {
|
||||||
inStream.getline(&buf[0], static_cast<std::streamsize>(maxchars));
|
inStream->getline(&buf[0], static_cast<std::streamsize>(maxchars));
|
||||||
|
|
||||||
std::string linebuf(&buf[0]);
|
std::string linebuf(&buf[0]);
|
||||||
|
|
||||||
@@ -624,9 +596,9 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
|
if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
|
||||||
// flush previous material.
|
// flush previous material.
|
||||||
if (!material.name.empty()) {
|
if (!material.name.empty()) {
|
||||||
material_map.insert(std::pair<std::string, int>(
|
material_map->insert(std::pair<std::string, int>(
|
||||||
material.name, static_cast<int>(materials.size())));
|
material.name, static_cast<int>(materials->size())));
|
||||||
materials.push_back(material);
|
materials->push_back(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial temporary material
|
// initial temporary material
|
||||||
@@ -803,15 +775,15 @@ void LoadMtl(std::map<std::string, int> &material_map,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// flush last material.
|
// flush last material.
|
||||||
material_map.insert(std::pair<std::string, int>(
|
material_map->insert(std::pair<std::string, int>(
|
||||||
material.name, static_cast<int>(materials.size())));
|
material.name, static_cast<int>(materials->size())));
|
||||||
materials.push_back(material);
|
materials->push_back(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaterialFileReader::operator()(const std::string &matId,
|
bool MaterialFileReader::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) {
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
|
||||||
if (!m_mtlBasePath.empty()) {
|
if (!m_mtlBasePath.empty()) {
|
||||||
@@ -821,29 +793,37 @@ bool MaterialFileReader::operator()(const std::string &matId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::ifstream matIStream(filepath.c_str());
|
std::ifstream matIStream(filepath.c_str());
|
||||||
LoadMtl(matMap, materials, matIStream);
|
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. Created a default material.";
|
||||||
err += ss.str();
|
if (err) {
|
||||||
|
(*err) += ss.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
bool LoadObj(attrib_t *attrib,
|
||||||
std::vector<material_t> &materials, // [output]
|
std::vector<shape_t> *shapes,
|
||||||
std::string &err, const char *filename, const char *mtl_basepath,
|
std::vector<material_t> *materials,
|
||||||
|
std::string *err, const char *filename, const char *mtl_basepath,
|
||||||
bool trianglulate) {
|
bool trianglulate) {
|
||||||
|
|
||||||
shapes.clear();
|
attrib->positions.clear();
|
||||||
|
attrib->normals.clear();
|
||||||
|
attrib->texcoords.clear();
|
||||||
|
shapes->clear();
|
||||||
|
|
||||||
std::stringstream errss;
|
std::stringstream errss;
|
||||||
|
|
||||||
std::ifstream ifs(filename);
|
std::ifstream ifs(filename);
|
||||||
if (!ifs) {
|
if (!ifs) {
|
||||||
errss << "Cannot open file [" << filename << "]" << std::endl;
|
errss << "Cannot open file [" << filename << "]" << std::endl;
|
||||||
err = errss.str();
|
if (err) {
|
||||||
|
(*err) = errss.str();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,13 +833,14 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
}
|
}
|
||||||
MaterialFileReader matFileReader(basePath);
|
MaterialFileReader matFileReader(basePath);
|
||||||
|
|
||||||
return LoadObj(shapes, materials, err, ifs, matFileReader, trianglulate);
|
return LoadObj(attrib, shapes, materials, err, &ifs, &matFileReader, trianglulate);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
bool LoadObj(attrib_t *attrib,
|
||||||
std::vector<material_t> &materials, // [output]
|
std::vector<shape_t> *shapes,
|
||||||
std::string &err, std::istream &inStream,
|
std::vector<material_t> *materials,
|
||||||
MaterialReader &readMatFn, bool triangulate) {
|
std::string *err, std::istream *inStream,
|
||||||
|
MaterialReader *readMatFn, bool triangulate) {
|
||||||
std::stringstream errss;
|
std::stringstream errss;
|
||||||
|
|
||||||
std::vector<float> v;
|
std::vector<float> v;
|
||||||
@@ -871,15 +852,15 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
|
|
||||||
// material
|
// material
|
||||||
std::map<std::string, int> material_map;
|
std::map<std::string, int> material_map;
|
||||||
std::map<vertex_index, unsigned int> vertexCache;
|
//std::map<vertex_index, unsigned int> vertexCache;
|
||||||
int material = -1;
|
int material = -1;
|
||||||
|
|
||||||
shape_t shape;
|
shape_t shape;
|
||||||
|
|
||||||
int maxchars = 8192; // Alloc enough size.
|
int maxchars = 8192; // Alloc enough size.
|
||||||
std::vector<char> buf(static_cast<size_t>(maxchars)); // Alloc enough size.
|
std::vector<char> buf(static_cast<size_t>(maxchars)); // Alloc enough size.
|
||||||
while (inStream.peek() != -1) {
|
while (inStream->peek() != -1) {
|
||||||
inStream.getline(&buf[0], maxchars);
|
inStream->getline(&buf[0], maxchars);
|
||||||
|
|
||||||
std::string linebuf(&buf[0]);
|
std::string linebuf(&buf[0]);
|
||||||
|
|
||||||
@@ -985,8 +966,8 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
|
|
||||||
if (newMaterialId != material) {
|
if (newMaterialId != material) {
|
||||||
// Create per-face material
|
// Create per-face material
|
||||||
exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags,
|
exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags,
|
||||||
material, name, true, triangulate);
|
material, name, triangulate);
|
||||||
faceGroup.clear();
|
faceGroup.clear();
|
||||||
material = newMaterialId;
|
material = newMaterialId;
|
||||||
}
|
}
|
||||||
@@ -1005,8 +986,10 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
#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);
|
||||||
err += err_mtl;
|
if (err) {
|
||||||
|
(*err) += err_mtl;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
faceGroup.clear(); // for safety
|
faceGroup.clear(); // for safety
|
||||||
@@ -1021,10 +1004,10 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
|
|
||||||
// flush previous face group.
|
// flush previous face group.
|
||||||
bool ret =
|
bool ret =
|
||||||
exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags,
|
exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags,
|
||||||
material, name, true, triangulate);
|
material, name, triangulate);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
shapes.push_back(shape);
|
shapes->push_back(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
shape = shape_t();
|
shape = shape_t();
|
||||||
@@ -1058,10 +1041,10 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
|
|
||||||
// flush previous face group.
|
// flush previous face group.
|
||||||
bool ret =
|
bool ret =
|
||||||
exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags,
|
exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags,
|
||||||
material, name, true, triangulate);
|
material, name, triangulate);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
shapes.push_back(shape);
|
shapes->push_back(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
// material = -1;
|
// material = -1;
|
||||||
@@ -1129,14 +1112,21 @@ bool LoadObj(std::vector<shape_t> &shapes, // [output]
|
|||||||
// Ignore unknown command.
|
// Ignore unknown command.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup,
|
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup,
|
||||||
tags, material, name, true, triangulate);
|
tags, material, name, triangulate);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
shapes.push_back(shape);
|
shapes->push_back(shape);
|
||||||
}
|
}
|
||||||
faceGroup.clear(); // for safety
|
faceGroup.clear(); // for safety
|
||||||
|
|
||||||
err += errss.str();
|
if (err) {
|
||||||
|
(*err) += errss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
attrib->positions.swap(v);
|
||||||
|
attrib->normals.swap(vn);
|
||||||
|
attrib->texcoords.swap(vt);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user