Compare commits
13 Commits
tigrazone-
...
devel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
609139f370 | ||
|
|
cc73127bf0 | ||
|
|
160d6be10f | ||
|
|
583590767e | ||
|
|
dc542d6638 | ||
|
|
c5976f931b | ||
|
|
0511658e86 | ||
|
|
54851f8ac7 | ||
|
|
a6c1d07560 | ||
|
|
4fe479453b | ||
|
|
af1bcf1e11 | ||
|
|
7b6e33da52 | ||
|
|
5896933508 |
33
README.md
33
README.md
@@ -26,11 +26,20 @@ Old version is available `v0.9.x` branch https://github.com/syoyo/tinyobjloader/
|
||||
|
||||
## What's new
|
||||
|
||||
### Version 2.x
|
||||
|
||||
* Refactor API
|
||||
* Support triangulation for concave polygons(#151)
|
||||
|
||||
### Version 1.x
|
||||
|
||||
Avaiable in `v1.x.y` branch.
|
||||
|
||||
* 20 Aug, 2016 : Bump version v1.0.0. New data structure and API!
|
||||
|
||||
### Old version
|
||||
### Older version
|
||||
|
||||
Previous old version is avaiable in `v0.9.x` branch.
|
||||
Older version is avaiable in `v0.9.x` branch.
|
||||
|
||||
## Example
|
||||
|
||||
@@ -49,7 +58,11 @@ http://casual-effects.com/data/index.html
|
||||
|
||||
TinyObjLoader is successfully used in ...
|
||||
|
||||
### New version(v1.0.x)
|
||||
### New version(v2.x)
|
||||
|
||||
* Your project here! (Letting us know via github issue is welcome!)
|
||||
|
||||
### Old version(v1.x)
|
||||
|
||||
* Double precision support through `TINYOBJLOADER_USE_DOUBLE` thanks to noma
|
||||
* Loading models in Vulkan Tutorial https://vulkan-tutorial.com/Loading_models
|
||||
@@ -60,7 +73,7 @@ TinyObjLoader is successfully used in ...
|
||||
* VFPR - a Vulkan Forward Plus Renderer : https://github.com/WindyDarian/Vulkan-Forward-Plus-Renderer
|
||||
* Your project here! (Letting us know via github issue is welcome!)
|
||||
|
||||
### Old version(v0.9.x)
|
||||
### Older version(v0.9.x)
|
||||
|
||||
* bullet3 https://github.com/erwincoumans/bullet3
|
||||
* pbrt-v2 https://github.com/mmp/pbrt-v2
|
||||
@@ -228,12 +241,12 @@ for (size_t s = 0; s < shapes.size(); s++) {
|
||||
for (size_t v = 0; v < fv; v++) {
|
||||
// access to vertex
|
||||
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
|
||||
tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0];
|
||||
tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1];
|
||||
tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2];
|
||||
tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0];
|
||||
tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1];
|
||||
tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2];
|
||||
tinyobj::real_t vx = attrib.vertices[idx.vertex_index].x;
|
||||
tinyobj::real_t vy = attrib.vertices[idx.vertex_index].y;
|
||||
tinyobj::real_t vz = attrib.vertices[idx.vertex_index].z;
|
||||
tinyobj::real_t nx = attrib.normals[idx.normal_index].x;
|
||||
tinyobj::real_t ny = attrib.normals[idx.normal_index].y;
|
||||
tinyobj::real_t nz = attrib.normals[idx.normal_index].z;
|
||||
tinyobj::real_t tx = attrib.texcoords[2*idx.texcoord_index+0];
|
||||
tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1];
|
||||
// Optional: vertex colors
|
||||
|
||||
@@ -29,6 +29,12 @@ extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class timerutil {
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
@@ -106,24 +112,24 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
|
||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||
std::cout << "# of materials : " << materials.size() << std::endl;
|
||||
|
||||
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
|
||||
for (size_t v = 0; v < attrib.vertices.size(); v++) {
|
||||
printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
|
||||
static_cast<const double>(attrib.vertices[3 * v + 0]),
|
||||
static_cast<const double>(attrib.vertices[3 * v + 1]),
|
||||
static_cast<const double>(attrib.vertices[3 * v + 2]));
|
||||
static_cast<const double>(attrib.vertices[v].x),
|
||||
static_cast<const double>(attrib.vertices[v].y),
|
||||
static_cast<const double>(attrib.vertices[v].z));
|
||||
}
|
||||
|
||||
for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
|
||||
for (size_t v = 0; v < attrib.normals.size(); v++) {
|
||||
printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(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]));
|
||||
static_cast<const double>(attrib.normals[v].x),
|
||||
static_cast<const double>(attrib.normals[v].y),
|
||||
static_cast<const double>(attrib.normals[v].z));
|
||||
}
|
||||
|
||||
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
|
||||
for (size_t v = 0; v < attrib.texcoords.size(); v++) {
|
||||
printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v),
|
||||
static_cast<const double>(attrib.texcoords[2 * v + 0]),
|
||||
static_cast<const double>(attrib.texcoords[2 * v + 1]));
|
||||
static_cast<const double>(attrib.texcoords[v].x),
|
||||
static_cast<const double>(attrib.texcoords[v].y));
|
||||
}
|
||||
|
||||
// For each shape
|
||||
|
||||
@@ -22,22 +22,22 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
|
||||
|
||||
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
|
||||
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||
static_cast<const double>(attrib.vertices[3*v+0]),
|
||||
static_cast<const double>(attrib.vertices[3*v+1]),
|
||||
static_cast<const double>(attrib.vertices[3*v+2]));
|
||||
static_cast<const double>(attrib.vertices[v].x),
|
||||
static_cast<const double>(attrib.vertices[v].y),
|
||||
static_cast<const double>(attrib.vertices[v].z));
|
||||
}
|
||||
|
||||
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]));
|
||||
static_cast<const double>(attrib.normals[v].x),
|
||||
static_cast<const double>(attrib.normals[v].y),
|
||||
static_cast<const double>(attrib.normals[v].z));
|
||||
}
|
||||
|
||||
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]));
|
||||
static_cast<const double>(attrib.texcoords[v].x),
|
||||
static_cast<const double>(attrib.texcoords[v].y));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
@@ -303,7 +303,8 @@ std::string matStream(
|
||||
virtual bool operator() (
|
||||
const std::string& matId,
|
||||
std::vector<material_t>* materials,
|
||||
std::map<unsigned int, int>* matMap,
|
||||
//std::map<std::string, int>* matMap,
|
||||
std::map<uint32_t, int>* matMap,
|
||||
std::string* err)
|
||||
{
|
||||
(void)matId;
|
||||
|
||||
@@ -23,7 +23,8 @@ THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//
|
||||
// version 1.1.2 : Used new hashed keywords
|
||||
// version 2.1.0 : Used new hashed keywords
|
||||
// version 2.0.0 : New API! And support triangulation of concave polygon(#151).
|
||||
// version 1.1.0 : Support parsing vertex color(#144)
|
||||
// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138)
|
||||
// version 1.0.7 : Support multiple tex options(#126)
|
||||
@@ -52,6 +53,13 @@ THE SOFTWARE.
|
||||
|
||||
namespace tinyobj {
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ...
|
||||
//
|
||||
// -blendu on | off # set horizontal texture blending
|
||||
@@ -109,6 +117,44 @@ typedef double real_t;
|
||||
typedef float real_t;
|
||||
#endif
|
||||
|
||||
struct vec3_t {
|
||||
real_t x, y, z;
|
||||
};
|
||||
inline vec3_t operator+(const vec3_t &l, const vec3_t &r) {
|
||||
vec3_t o;
|
||||
o.x = l.x + r.x;
|
||||
o.y = l.y + r.y;
|
||||
o.z = l.z + r.z;
|
||||
return o;
|
||||
}
|
||||
inline vec3_t operator-(const vec3_t &l, const vec3_t &r) {
|
||||
vec3_t o;
|
||||
o.x = l.x - r.x;
|
||||
o.y = l.y - r.y;
|
||||
o.z = l.z - r.z;
|
||||
return o;
|
||||
}
|
||||
inline vec3_t operator*(const vec3_t &l, real_t r) {
|
||||
vec3_t o;
|
||||
o.x = l.x * r;
|
||||
o.y = l.y * r;
|
||||
o.z = l.z * r;
|
||||
return o;
|
||||
}
|
||||
inline vec3_t cross(const vec3_t &l, const vec3_t &r) {
|
||||
vec3_t o;
|
||||
o.x = l.y * r.z - r.y * l.z;
|
||||
o.y = l.z * r.x - r.z * l.x;
|
||||
o.z = l.x * r.y - r.x * l.y;
|
||||
return o;
|
||||
}
|
||||
inline real_t dot(const vec3_t &l, const vec3_t &r) {
|
||||
return l.x * r.x + l.y * r.y + l.z * r.z;
|
||||
}
|
||||
struct vec2_t {
|
||||
real_t x, y;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TEXTURE_TYPE_NONE, // default
|
||||
TEXTURE_TYPE_SPHERE,
|
||||
@@ -229,9 +275,9 @@ typedef struct {
|
||||
|
||||
// Vertex attributes
|
||||
typedef struct {
|
||||
std::vector<real_t> vertices; // 'v'
|
||||
std::vector<real_t> normals; // 'vn'
|
||||
std::vector<real_t> texcoords; // 'vt'
|
||||
std::vector<vec3_t> vertices; // 'v'
|
||||
std::vector<vec3_t> normals; // 'vn'
|
||||
std::vector<vec2_t> texcoords; // 'vt'
|
||||
std::vector<real_t> colors; // extension: vertex colors
|
||||
} attrib_t;
|
||||
|
||||
@@ -290,7 +336,8 @@ class MaterialFileReader : public MaterialReader {
|
||||
virtual bool operator()(const std::string &matId,
|
||||
std::vector<material_t> *materials,
|
||||
// std::map<std::string, int> *matMap,
|
||||
std::map<unsigned int, int> *matMap, std::string *err);
|
||||
std::map<unsigned int, int> *matMap,
|
||||
std::string *err);
|
||||
|
||||
private:
|
||||
std::string m_mtlBaseDir;
|
||||
@@ -304,7 +351,8 @@ class MaterialStreamReader : public MaterialReader {
|
||||
virtual bool operator()(const std::string &matId,
|
||||
std::vector<material_t> *materials,
|
||||
// std::map<std::string, int> *matMap,
|
||||
std::map<unsigned int, int> *matMap, std::string *err);
|
||||
std::map<unsigned int, int> *matMap,
|
||||
std::string *err);
|
||||
|
||||
private:
|
||||
std::istream &m_inStream;
|
||||
@@ -348,8 +396,9 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
/// Loads materials into std::map
|
||||
void LoadMtl(
|
||||
// std::map<std::string, int> *material_map,
|
||||
std::map<unsigned int, int> *material_map, std::vector<material_t> *materials,
|
||||
std::istream *inStream, std::string *warning);
|
||||
std::map<unsigned int, int> *material_map,
|
||||
std::vector<material_t> *materials, std::istream *inStream,
|
||||
std::string *warning);
|
||||
|
||||
} // namespace tinyobj
|
||||
|
||||
@@ -367,10 +416,9 @@ void LoadMtl(
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// #define TINYOBJLOADER_IMPLEMENTATION_BUFREAD
|
||||
//#define TINYOBJLOADER_IMPLEMENTATION_BUFREAD
|
||||
|
||||
#ifdef TINYOBJLOADER_IMPLEMENTATION_BUFREAD
|
||||
// TODO(syoyo): Support non-win32 system
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -442,11 +490,14 @@ class ImportInBuf : public std::streambuf {
|
||||
|
||||
char *buffer_;
|
||||
int fd_;
|
||||
unsigned long long fsize_, pos_;
|
||||
uint64_t fsize_, pos_;
|
||||
size_t buf_sz;
|
||||
};
|
||||
#endif
|
||||
|
||||
//***************************************************
|
||||
//*************** tigro keywords hash functions begin
|
||||
|
||||
// tigra: x31 hash function
|
||||
|
||||
typedef unsigned int khint_t;
|
||||
@@ -461,7 +512,8 @@ inline unsigned int X31_hash_stringSZ(const char *s, int sz) {
|
||||
int i;
|
||||
khint_t h = static_cast<khint_t>(*s);
|
||||
|
||||
for (++s, i = sz - 1; i && *s; ++s, i--) h = (h << 5) - h + static_cast<khint_t>(*s);
|
||||
for (++s, i = sz - 1; i && *s; ++s, i--)
|
||||
h = (h << 5) - h + static_cast<khint_t>(*s);
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -579,10 +631,12 @@ enum tokens_enum {
|
||||
TOK_norm
|
||||
};
|
||||
|
||||
// TODO(syoyo): Do not define in global scope.
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#endif
|
||||
|
||||
static std::map<unsigned int, int> hashed_toks;
|
||||
@@ -591,7 +645,7 @@ static std::map<unsigned int, int> hashed_toks;
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
// functions!
|
||||
static void initHashedTokensMap() {
|
||||
// init hashed tokens map
|
||||
|
||||
@@ -607,19 +661,22 @@ static void initHashedTokensMap() {
|
||||
// init hashed tokens map END
|
||||
}
|
||||
|
||||
// search token in keywords hash map
|
||||
static int token2tok(const char *token) {
|
||||
unsigned int token_sz, a_hash;
|
||||
|
||||
int a_tok;
|
||||
|
||||
token_sz = static_cast<unsigned int>(strpbrk(token, " \t\r") - token); // token length
|
||||
token_sz = static_cast<unsigned int>(strpbrk(token, " \t\r") -
|
||||
token); // token length
|
||||
|
||||
if (token_sz < 1) // delimiter not found, token_sz = strlen(token)
|
||||
{
|
||||
// token_sz=strlen(token);
|
||||
a_hash = X31_hash_string(token);
|
||||
} else
|
||||
} else {
|
||||
a_hash = X31_hash_stringSZ(token, static_cast<int>(token_sz));
|
||||
}
|
||||
|
||||
a_tok = -1;
|
||||
if (hashed_toks.find(a_hash) != hashed_toks.end())
|
||||
@@ -628,6 +685,9 @@ static int token2tok(const char *token) {
|
||||
return a_tok;
|
||||
}
|
||||
|
||||
//*************** tigro keywords hash functions END
|
||||
//*************************************************
|
||||
|
||||
MaterialReader::~MaterialReader() {}
|
||||
|
||||
struct vertex_index {
|
||||
@@ -1228,6 +1288,7 @@ static bool ParseTextureNameAndOption(std::string *texname,
|
||||
parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0,
|
||||
1.0);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Assume texture filename
|
||||
#if 0
|
||||
@@ -1296,7 +1357,7 @@ static void InitMaterial(material_t *material) {
|
||||
static bool exportFaceGroupToShape(
|
||||
shape_t *shape, const std::vector<std::vector<vertex_index> > &faceGroup,
|
||||
const std::vector<tag_t> &tags, const int material_id,
|
||||
const std::string &name, bool triangulate) {
|
||||
const std::string &name, bool triangulate, const std::vector<vec3_t> &v) {
|
||||
if (faceGroup.empty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1312,28 +1373,128 @@ static bool exportFaceGroupToShape(
|
||||
size_t npolys = face.size();
|
||||
|
||||
if (triangulate) {
|
||||
// Polygon -> triangle fan conversion
|
||||
for (size_t k = 2; k < npolys; k++) {
|
||||
i1 = i2;
|
||||
i2 = face[k];
|
||||
vec3_t face_normal = {0, 0, 0};
|
||||
|
||||
index_t idx0, idx1, idx2;
|
||||
idx0.vertex_index = i0.v_idx;
|
||||
idx0.normal_index = i0.vn_idx;
|
||||
idx0.texcoord_index = i0.vt_idx;
|
||||
idx1.vertex_index = i1.v_idx;
|
||||
idx1.normal_index = i1.vn_idx;
|
||||
idx1.texcoord_index = i1.vt_idx;
|
||||
idx2.vertex_index = i2.v_idx;
|
||||
idx2.normal_index = i2.vn_idx;
|
||||
idx2.texcoord_index = i2.vt_idx;
|
||||
for (size_t k = 0; k < npolys; ++k) {
|
||||
int vi0 = face[(k + 0) % npolys].v_idx;
|
||||
int vi1 = face[(k + 1) % npolys].v_idx;
|
||||
int vi2 = face[(k + 2) % npolys].v_idx;
|
||||
const vec3_t &v0 = v[size_t(vi0)];
|
||||
const vec3_t &v1 = v[size_t(vi1)];
|
||||
const vec3_t &v2 = v[size_t(vi2)];
|
||||
const vec3_t e0 = v1 - v0;
|
||||
const vec3_t e1 = v2 - v1;
|
||||
const vec3_t n = cross(e0, e1);
|
||||
face_normal = face_normal + n;
|
||||
}
|
||||
|
||||
shape->mesh.indices.push_back(idx0);
|
||||
shape->mesh.indices.push_back(idx1);
|
||||
shape->mesh.indices.push_back(idx2);
|
||||
// face_normal is currently area of face
|
||||
{
|
||||
real_t l = std::sqrt(dot(face_normal, face_normal));
|
||||
face_normal = face_normal * (static_cast<real_t>(1.0) / l);
|
||||
}
|
||||
|
||||
shape->mesh.num_face_vertices.push_back(3);
|
||||
shape->mesh.material_ids.push_back(material_id);
|
||||
int maxRounds =
|
||||
10; // arbitrary max loop count to protect against unexpected errors
|
||||
|
||||
std::vector<vertex_index> remainingFace = face;
|
||||
size_t guess_vert = 0;
|
||||
while (remainingFace.size() > 3 && maxRounds > 0) {
|
||||
npolys = remainingFace.size();
|
||||
if (guess_vert >= npolys) {
|
||||
maxRounds -= 1;
|
||||
guess_vert -= npolys;
|
||||
}
|
||||
i0 = remainingFace[(guess_vert + 0) % npolys];
|
||||
i1 = remainingFace[(guess_vert + 1) % npolys];
|
||||
i2 = remainingFace[(guess_vert + 2) % npolys];
|
||||
int vi0 = i0.v_idx;
|
||||
int vi1 = i1.v_idx;
|
||||
int vi2 = i2.v_idx;
|
||||
const vec3_t &v0 = v[size_t(vi0)];
|
||||
const vec3_t &v1 = v[size_t(vi1)];
|
||||
const vec3_t &v2 = v[size_t(vi2)];
|
||||
const vec3_t e0 = v1 - v0;
|
||||
const vec3_t e1 = v2 - v1;
|
||||
const vec3_t n = cross(e0, e1);
|
||||
bool internal = dot(n, face_normal) < 0.0f;
|
||||
if (internal) {
|
||||
guess_vert += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check all other verts in case they are inside this triangle
|
||||
bool overlap = false;
|
||||
for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
|
||||
int ovi = remainingFace[(guess_vert + otherVert) % npolys].v_idx;
|
||||
const vec3_t &ov = v[size_t(ovi)];
|
||||
if (dot(face_normal, cross(e0, ov - v0)) < 0) continue;
|
||||
if (dot(face_normal, cross(e1, ov - v1)) < 0) continue;
|
||||
if (dot(face_normal, cross(v0 - v2, ov - v2)) < 0) continue;
|
||||
// vert inside triangle
|
||||
overlap = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (overlap) {
|
||||
guess_vert += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// this triangle is an ear
|
||||
{
|
||||
index_t idx0, idx1, idx2;
|
||||
idx0.vertex_index = i0.v_idx;
|
||||
idx0.normal_index = i0.vn_idx;
|
||||
idx0.texcoord_index = i0.vt_idx;
|
||||
idx1.vertex_index = i1.v_idx;
|
||||
idx1.normal_index = i1.vn_idx;
|
||||
idx1.texcoord_index = i1.vt_idx;
|
||||
idx2.vertex_index = i2.v_idx;
|
||||
idx2.normal_index = i2.vn_idx;
|
||||
idx2.texcoord_index = i2.vt_idx;
|
||||
|
||||
shape->mesh.indices.push_back(idx0);
|
||||
shape->mesh.indices.push_back(idx1);
|
||||
shape->mesh.indices.push_back(idx2);
|
||||
|
||||
shape->mesh.num_face_vertices.push_back(3);
|
||||
shape->mesh.material_ids.push_back(material_id);
|
||||
}
|
||||
|
||||
// remove v1 from the list
|
||||
size_t removed_vert_index = (guess_vert + 1) % npolys;
|
||||
while (removed_vert_index + 1 < npolys) {
|
||||
remainingFace[removed_vert_index] =
|
||||
remainingFace[removed_vert_index + 1];
|
||||
removed_vert_index += 1;
|
||||
}
|
||||
remainingFace.pop_back();
|
||||
}
|
||||
|
||||
if (remainingFace.size() == 3) {
|
||||
i0 = remainingFace[0];
|
||||
i1 = remainingFace[1];
|
||||
i2 = remainingFace[2];
|
||||
{
|
||||
index_t idx0, idx1, idx2;
|
||||
idx0.vertex_index = i0.v_idx;
|
||||
idx0.normal_index = i0.vn_idx;
|
||||
idx0.texcoord_index = i0.vt_idx;
|
||||
idx1.vertex_index = i1.v_idx;
|
||||
idx1.normal_index = i1.vn_idx;
|
||||
idx1.texcoord_index = i1.vt_idx;
|
||||
idx2.vertex_index = i2.v_idx;
|
||||
idx2.normal_index = i2.vn_idx;
|
||||
idx2.texcoord_index = i2.vt_idx;
|
||||
|
||||
shape->mesh.indices.push_back(idx0);
|
||||
shape->mesh.indices.push_back(idx1);
|
||||
shape->mesh.indices.push_back(idx2);
|
||||
|
||||
shape->mesh.num_face_vertices.push_back(3);
|
||||
shape->mesh.material_ids.push_back(material_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t k = 0; k < npolys; k++) {
|
||||
@@ -1370,8 +1531,9 @@ static void SplitString(const std::string &s, char delim,
|
||||
|
||||
void LoadMtl(
|
||||
// std::map<std::string, int> *material_map,
|
||||
std::map<unsigned int, int> *material_map, std::vector<material_t> *materials,
|
||||
std::istream *inStream, std::string *warning) {
|
||||
std::map<unsigned int, int> *material_map,
|
||||
std::vector<material_t> *materials, std::istream *inStream,
|
||||
std::string *warning) {
|
||||
// Create a default material anyway.
|
||||
material_t material;
|
||||
InitMaterial(&material);
|
||||
@@ -1424,71 +1586,59 @@ void LoadMtl(
|
||||
if (IS_SPACE((token[2]))) {
|
||||
// group K
|
||||
if (token[0] == 'K') {
|
||||
switch (token[1]) {
|
||||
case 'a':
|
||||
// ambient
|
||||
// if (token[1] == 'a')
|
||||
{
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.ambient[0] = r;
|
||||
material.ambient[1] = g;
|
||||
material.ambient[2] = b;
|
||||
continue;
|
||||
}
|
||||
// ambient
|
||||
if (token[1] == 'a') {
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.ambient[0] = r;
|
||||
material.ambient[1] = g;
|
||||
material.ambient[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// diffuse
|
||||
case 'd':
|
||||
// if (token[1] == 'd')
|
||||
{
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.diffuse[0] = r;
|
||||
material.diffuse[1] = g;
|
||||
material.diffuse[2] = b;
|
||||
continue;
|
||||
}
|
||||
// diffuse
|
||||
if (token[1] == 'd') {
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.diffuse[0] = r;
|
||||
material.diffuse[1] = g;
|
||||
material.diffuse[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// specular
|
||||
case 's':
|
||||
// if (token[1] == 's')
|
||||
{
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.specular[0] = r;
|
||||
material.specular[1] = g;
|
||||
material.specular[2] = b;
|
||||
continue;
|
||||
}
|
||||
// specular
|
||||
if (token[1] == 's') {
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.specular[0] = r;
|
||||
material.specular[1] = g;
|
||||
material.specular[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// transmittance
|
||||
case 't':
|
||||
// if (token[1] == 't')
|
||||
{
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.transmittance[0] = r;
|
||||
material.transmittance[1] = g;
|
||||
material.transmittance[2] = b;
|
||||
continue;
|
||||
}
|
||||
// transmittance
|
||||
if (token[1] == 't') {
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.transmittance[0] = r;
|
||||
material.transmittance[1] = g;
|
||||
material.transmittance[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// emission
|
||||
case 'e':
|
||||
// if (token[1] == 'e')
|
||||
{
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.emission[0] = r;
|
||||
material.emission[1] = g;
|
||||
material.emission[2] = b;
|
||||
continue;
|
||||
}
|
||||
// emission
|
||||
if (token[1] == 'e') {
|
||||
token += 2;
|
||||
real_t r, g, b;
|
||||
parseReal3(&r, &g, &b, &token);
|
||||
material.emission[0] = r;
|
||||
material.emission[1] = g;
|
||||
material.emission[2] = b;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1517,6 +1667,51 @@ void LoadMtl(
|
||||
material.shininess = parseReal(&token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token[0] == 'T' && token[1] == 'r') {
|
||||
token += 2;
|
||||
if (has_d) {
|
||||
// `d` wins. Ignore `Tr` value.
|
||||
ss << "WARN: Both `d` and `Tr` parameters defined for \""
|
||||
<< material.name << "\". Use the value of `d` for dissolve."
|
||||
<< std::endl;
|
||||
} else {
|
||||
// We invert value of Tr(assume Tr is in range [0, 1])
|
||||
// NOTE: Interpretation of Tr is application(exporter) dependent. For
|
||||
// some application(e.g. 3ds max obj exporter), Tr = d(Issue 43)
|
||||
material.dissolve = 1.0f - parseReal(&token);
|
||||
}
|
||||
has_tr = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// tigra: refactoring for new speedup release
|
||||
if (token[0] == 'P') {
|
||||
// PBR: roughness
|
||||
if (token[1] == 'r') {
|
||||
token += 2;
|
||||
material.roughness = parseReal(&token);
|
||||
continue;
|
||||
} else
|
||||
// PBR: metallic
|
||||
if (token[1] == 'm') {
|
||||
token += 2;
|
||||
material.metallic = parseReal(&token);
|
||||
continue;
|
||||
} else
|
||||
// PBR: sheen
|
||||
if (token[1] == 's') {
|
||||
token += 2;
|
||||
material.sheen = parseReal(&token);
|
||||
continue;
|
||||
} else
|
||||
// PBR: clearcoat thickness
|
||||
if (token[1] == 'c') {
|
||||
token += 2;
|
||||
material.clearcoat_thickness = parseReal(&token);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dissolve
|
||||
@@ -1532,43 +1727,6 @@ void LoadMtl(
|
||||
has_d = true;
|
||||
continue;
|
||||
}
|
||||
if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
if (has_d) {
|
||||
// `d` wins. Ignore `Tr` value.
|
||||
ss << "WARN: Both `d` and `Tr` parameters defined for \""
|
||||
<< material.name << "\". Use the value of `d` for dissolve."
|
||||
<< std::endl;
|
||||
} else {
|
||||
// We invert value of Tr(assume Tr is in range [0, 1])
|
||||
// NOTE: Interpretation of Tr is application(exporter) dependent. For
|
||||
// some application(e.g. 3ds max obj exporter), Tr = d(Issue 43)
|
||||
material.dissolve = 1.0f - parseReal(&token);
|
||||
}
|
||||
has_tr = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// tigra: refactoring for new speedup release
|
||||
if (token[0] == 'P' && IS_SPACE(token[2])) {
|
||||
token += 2;
|
||||
|
||||
// PBR: roughness
|
||||
if (token[1] == 'r')
|
||||
material.roughness = parseReal(&token);
|
||||
else
|
||||
// PBR: metallic
|
||||
if (token[1] == 'm')
|
||||
material.metallic = parseReal(&token);
|
||||
else
|
||||
// PBR: sheen
|
||||
if (token[1] == 's')
|
||||
material.sheen = parseReal(&token);
|
||||
else
|
||||
// PBR: clearcoat thickness
|
||||
if (token[1] == 'c')
|
||||
material.clearcoat_thickness = parseReal(&token);
|
||||
}
|
||||
|
||||
a_tok = token2tok(token);
|
||||
|
||||
@@ -1940,9 +2098,9 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
bool triangulate) {
|
||||
std::stringstream errss;
|
||||
|
||||
std::vector<real_t> v;
|
||||
std::vector<real_t> vn;
|
||||
std::vector<real_t> vt;
|
||||
std::vector<vec3_t> v;
|
||||
std::vector<vec3_t> vn;
|
||||
std::vector<vec2_t> vt;
|
||||
std::vector<real_t> vc;
|
||||
std::vector<tag_t> tags;
|
||||
std::vector<std::vector<vertex_index> > faceGroup;
|
||||
@@ -1991,164 +2149,164 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
|
||||
if (token[0] == '#') continue; // comment line
|
||||
|
||||
// vertex
|
||||
if (token[0] == 'v' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
real_t x, y, z;
|
||||
real_t r, g, b;
|
||||
parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token);
|
||||
v.push_back(x);
|
||||
v.push_back(y);
|
||||
v.push_back(z);
|
||||
if (IS_SPACE((token[1]))) {
|
||||
// vertex
|
||||
if (token[0] == 'v') {
|
||||
token += 2;
|
||||
vec3_t vtx;
|
||||
real_t r, g, b;
|
||||
parseVertexWithColor(&vtx.x, &vtx.y, &vtx.z, &r, &g, &b, &token);
|
||||
v.push_back(vtx);
|
||||
|
||||
vc.push_back(r);
|
||||
vc.push_back(g);
|
||||
vc.push_back(b);
|
||||
continue;
|
||||
}
|
||||
vc.push_back(r);
|
||||
vc.push_back(g);
|
||||
vc.push_back(b);
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal
|
||||
if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
real_t x, y, z;
|
||||
parseReal3(&x, &y, &z, &token);
|
||||
vn.push_back(x);
|
||||
vn.push_back(y);
|
||||
vn.push_back(z);
|
||||
continue;
|
||||
}
|
||||
// face
|
||||
if (token[0] == 'f') {
|
||||
token += 2;
|
||||
token += strspn(token, " \t");
|
||||
|
||||
// texcoord
|
||||
if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
|
||||
token += 3;
|
||||
real_t x, y;
|
||||
parseReal2(&x, &y, &token);
|
||||
vt.push_back(x);
|
||||
vt.push_back(y);
|
||||
continue;
|
||||
}
|
||||
std::vector<vertex_index> face;
|
||||
face.reserve(3);
|
||||
|
||||
// face
|
||||
if (token[0] == 'f' && IS_SPACE((token[1]))) {
|
||||
token += 2;
|
||||
token += strspn(token, " \t");
|
||||
|
||||
std::vector<vertex_index> face;
|
||||
face.reserve(3);
|
||||
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
vertex_index vi;
|
||||
if (!parseTriple(&token, static_cast<int>(v.size() / 3),
|
||||
static_cast<int>(vn.size() / 3),
|
||||
static_cast<int>(vt.size() / 2), &vi)) {
|
||||
if (err) {
|
||||
(*err) = "Failed parse `f' line(e.g. zero value for face index).\n";
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
vertex_index vi;
|
||||
if (!parseTriple(&token, static_cast<int>(v.size() / 3),
|
||||
static_cast<int>(vn.size() / 3),
|
||||
static_cast<int>(vt.size() / 2), &vi)) {
|
||||
if (err) {
|
||||
(*err) =
|
||||
"Failed parse `f' line(e.g. zero value for face index).\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
face.push_back(vi);
|
||||
size_t n = strspn(token, " \t\r");
|
||||
token += n;
|
||||
}
|
||||
|
||||
face.push_back(vi);
|
||||
size_t n = strspn(token, " \t\r");
|
||||
token += n;
|
||||
// replace with emplace_back + std::move on C++11
|
||||
faceGroup.push_back(std::vector<vertex_index>());
|
||||
faceGroup[faceGroup.size() - 1].swap(face);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// replace with emplace_back + std::move on C++11
|
||||
faceGroup.push_back(std::vector<vertex_index>());
|
||||
faceGroup[faceGroup.size() - 1].swap(face);
|
||||
// group name
|
||||
if (token[0] == 'g') {
|
||||
// flush previous face group.
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material,
|
||||
name, triangulate, v);
|
||||
(void)ret; // return value not used.
|
||||
|
||||
continue;
|
||||
}
|
||||
if (shape.mesh.indices.size() > 0) {
|
||||
shapes->push_back(shape);
|
||||
}
|
||||
|
||||
// group name
|
||||
if (token[0] == 'g' && IS_SPACE((token[1]))) {
|
||||
// flush previous face group.
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||
triangulate);
|
||||
(void)ret; // return value not used.
|
||||
shape = shape_t();
|
||||
|
||||
if (shape.mesh.indices.size() > 0) {
|
||||
shapes->push_back(shape);
|
||||
// material = -1;
|
||||
faceGroup.clear();
|
||||
|
||||
std::vector<std::string> names;
|
||||
names.reserve(2);
|
||||
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
std::string str = parseString(&token);
|
||||
names.push_back(str);
|
||||
token += strspn(token, " \t\r"); // skip tag
|
||||
}
|
||||
|
||||
assert(names.size() > 0);
|
||||
|
||||
// names[0] must be 'g', so skip the 0th element.
|
||||
if (names.size() > 1) {
|
||||
name = names[1];
|
||||
} else {
|
||||
name = "";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
shape = shape_t();
|
||||
// object name
|
||||
if (token[0] == 'o') {
|
||||
// flush previous face group.
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material,
|
||||
name, triangulate, v);
|
||||
if (ret) {
|
||||
shapes->push_back(shape);
|
||||
}
|
||||
|
||||
// material = -1;
|
||||
faceGroup.clear();
|
||||
// material = -1;
|
||||
faceGroup.clear();
|
||||
shape = shape_t();
|
||||
|
||||
std::vector<std::string> names;
|
||||
names.reserve(2);
|
||||
// @todo { multiple object name? }
|
||||
token += 2;
|
||||
|
||||
while (!IS_NEW_LINE(token[0])) {
|
||||
std::string str = parseString(&token);
|
||||
names.push_back(str);
|
||||
token += strspn(token, " \t\r"); // skip tag
|
||||
}
|
||||
|
||||
assert(names.size() > 0);
|
||||
|
||||
// names[0] must be 'g', so skip the 0th element.
|
||||
if (names.size() > 1) {
|
||||
name = names[1];
|
||||
} else {
|
||||
name = "";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// object name
|
||||
if (token[0] == 'o' && IS_SPACE((token[1]))) {
|
||||
// flush previous face group.
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||
triangulate);
|
||||
if (ret) {
|
||||
shapes->push_back(shape);
|
||||
}
|
||||
|
||||
// material = -1;
|
||||
faceGroup.clear();
|
||||
shape = shape_t();
|
||||
|
||||
// @todo { multiple object name? }
|
||||
token += 2;
|
||||
|
||||
/*
|
||||
/*
|
||||
std::stringstream ss;
|
||||
ss << token;
|
||||
name = ss.str();
|
||||
*/
|
||||
*/
|
||||
|
||||
name = std::string(token);
|
||||
name = std::string(token);
|
||||
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token[0] == 't') {
|
||||
tag_t tag;
|
||||
|
||||
token += 2;
|
||||
|
||||
tag.name = parseString(&token);
|
||||
|
||||
tag_sizes ts = parseTagTriple(&token);
|
||||
|
||||
tag.intValues.resize(static_cast<size_t>(ts.num_ints));
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
|
||||
tag.intValues[i] = parseInt(&token);
|
||||
}
|
||||
|
||||
tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
|
||||
tag.floatValues[i] = parseReal(&token);
|
||||
}
|
||||
|
||||
tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
|
||||
tag.stringValues[i] = parseString(&token);
|
||||
}
|
||||
|
||||
tags.push_back(tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (token[0] == 't' && IS_SPACE(token[1])) {
|
||||
tag_t tag;
|
||||
|
||||
token += 2;
|
||||
|
||||
tag.name = parseString(&token);
|
||||
|
||||
tag_sizes ts = parseTagTriple(&token);
|
||||
|
||||
tag.intValues.resize(static_cast<size_t>(ts.num_ints));
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
|
||||
tag.intValues[i] = parseInt(&token);
|
||||
if (token[0] == 'v' && IS_SPACE((token[2]))) {
|
||||
// normal
|
||||
if (token[1] == 'n') {
|
||||
token += 3;
|
||||
vec3_t n;
|
||||
parseReal3(&n.x, &n.y, &n.z, &token);
|
||||
vn.push_back(n);
|
||||
continue;
|
||||
}
|
||||
|
||||
tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
|
||||
tag.floatValues[i] = parseReal(&token);
|
||||
// texcoord
|
||||
if (token[1] == 't') {
|
||||
token += 3;
|
||||
vec2_t tcoord;
|
||||
parseReal2(&tcoord.x, &tcoord.y, &token);
|
||||
vt.push_back(tcoord);
|
||||
continue;
|
||||
}
|
||||
|
||||
tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
|
||||
for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
|
||||
tag.stringValues[i] = parseString(&token);
|
||||
}
|
||||
|
||||
tags.push_back(tag);
|
||||
}
|
||||
|
||||
// tigra: refactoring for new speedup release
|
||||
@@ -2191,7 +2349,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
// this time.
|
||||
// just clear `faceGroup` after `exportFaceGroupToShape()` call.
|
||||
exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||
triangulate);
|
||||
triangulate, v);
|
||||
faceGroup.clear();
|
||||
material = newMaterialId;
|
||||
}
|
||||
@@ -2249,7 +2407,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
}
|
||||
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, tags, material, name,
|
||||
triangulate);
|
||||
triangulate, v);
|
||||
// exportFaceGroupToShape return false when `usemtl` is called in the last
|
||||
// line.
|
||||
// we also add `shape` to `shapes` when `shape.mesh` has already some
|
||||
@@ -2598,6 +2756,11 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace tinyobj
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user