add initial examples, replacing the 'Demos/Demos3'. Will make it work cross-platform, OpenGL3/OpenGL2 and add more examples to it.
This commit is contained in:
88
examples/ThirdPartyLibs/Wavefront/README.md
Normal file
88
examples/ThirdPartyLibs/Wavefront/README.md
Normal file
@@ -0,0 +1,88 @@
|
||||
tinyobjloader
|
||||
=============
|
||||
|
||||
http://syoyo.github.io/tinyobjloader/
|
||||
|
||||
Tiny but poweful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse 10M over polygons with moderate memory and time.
|
||||
|
||||
Good for embedding .obj loader to your (global illumination) renderer ;-)
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||

|
||||
|
||||
tinyobjloader can successfully load 6M triangles Rungholt scene.
|
||||
http://graphics.cs.williams.edu/data/meshes.xml
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Group
|
||||
* Vertex
|
||||
* Texcoord
|
||||
* Normal
|
||||
* Material
|
||||
* Unknown material attributes are treated as key-value.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Polygon is converted into triangle.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Licensed under 2 clause BSD.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
std::string inputfile = "cornell_box.obj";
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
|
||||
std::string err = tinyobj::LoadObj(shapes, inputfile.c_str());
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
||||
printf("shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
|
||||
printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]);
|
||||
}
|
||||
|
||||
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
||||
assert((shapes[i].mesh.positions.size() % 3) == 0);
|
||||
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
||||
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||
shapes[i].mesh.positions[3*v+0],
|
||||
shapes[i].mesh.positions[3*v+1],
|
||||
shapes[i].mesh.positions[3*v+2]);
|
||||
}
|
||||
|
||||
printf("shape[%ld].material.name = %s\n", i, shapes[i].material.name.c_str());
|
||||
printf(" material.Ka = (%f, %f ,%f)\n", shapes[i].material.ambient[0], shapes[i].material.ambient[1], shapes[i].material.ambient[2]);
|
||||
printf(" material.Kd = (%f, %f ,%f)\n", shapes[i].material.diffuse[0], shapes[i].material.diffuse[1], shapes[i].material.diffuse[2]);
|
||||
printf(" material.Ks = (%f, %f ,%f)\n", shapes[i].material.specular[0], shapes[i].material.specular[1], shapes[i].material.specular[2]);
|
||||
printf(" material.Tr = (%f, %f ,%f)\n", shapes[i].material.transmittance[0], shapes[i].material.transmittance[1], shapes[i].material.transmittance[2]);
|
||||
printf(" material.Ke = (%f, %f ,%f)\n", shapes[i].material.emission[0], shapes[i].material.emission[1], shapes[i].material.emission[2]);
|
||||
printf(" material.Ns = %f\n", shapes[i].material.shininess);
|
||||
printf(" material.map_Ka = %s\n", shapes[i].material.ambient_texname.c_str());
|
||||
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
||||
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
||||
printf(" material.map_Ns = %s\n", shapes[i].material.normal_texname.c_str());
|
||||
std::map<std::string, std::string>::iterator it(shapes[i].material.unknown_parameter.begin());
|
||||
std::map<std::string, std::string>::iterator itEnd(shapes[i].material.unknown_parameter.end());
|
||||
for (; it != itEnd; it++) {
|
||||
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
107
examples/ThirdPartyLibs/Wavefront/main.cpp
Normal file
107
examples/ThirdPartyLibs/Wavefront/main.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
static bool
|
||||
TestLoadObj(
|
||||
const char* fileName,
|
||||
bool verbose
|
||||
)
|
||||
{
|
||||
|
||||
|
||||
const char* prefix[]={"./data/","../data/","../../data/","../../../data/","../../../../data/"};
|
||||
char fullPath[1024];
|
||||
int index=-1;
|
||||
{
|
||||
|
||||
int numPrefixes = sizeof(prefix)/sizeof(char*);
|
||||
|
||||
for (int i=0;i<numPrefixes;i++)
|
||||
{
|
||||
|
||||
sprintf(fullPath,"%s%s",prefix[i],fileName);
|
||||
FILE* f;
|
||||
f = fopen(fullPath,"r");
|
||||
if (f)
|
||||
{
|
||||
index=i;
|
||||
fclose(f);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index<0)
|
||||
{
|
||||
printf("file not found %s\n", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Loading " << fullPath << std::endl;
|
||||
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::string err = tinyobj::LoadObj(shapes, fullPath, prefix[index]);
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "# of shapes : " << shapes.size() << std::endl;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
|
||||
printf("shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
|
||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
|
||||
printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]);
|
||||
}
|
||||
|
||||
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
|
||||
assert((shapes[i].mesh.positions.size() % 3) == 0);
|
||||
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
|
||||
printf(" v[%ld] = (%f, %f, %f)\n", v,
|
||||
shapes[i].mesh.positions[3*v+0],
|
||||
shapes[i].mesh.positions[3*v+1],
|
||||
shapes[i].mesh.positions[3*v+2]);
|
||||
}
|
||||
|
||||
printf("shape[%ld].material.name = %s\n", i, shapes[i].material.name.c_str());
|
||||
printf(" material.Ka = (%f, %f ,%f)\n", shapes[i].material.ambient[0], shapes[i].material.ambient[1], shapes[i].material.ambient[2]);
|
||||
printf(" material.Kd = (%f, %f ,%f)\n", shapes[i].material.diffuse[0], shapes[i].material.diffuse[1], shapes[i].material.diffuse[2]);
|
||||
printf(" material.Ks = (%f, %f ,%f)\n", shapes[i].material.specular[0], shapes[i].material.specular[1], shapes[i].material.specular[2]);
|
||||
printf(" material.Tr = (%f, %f ,%f)\n", shapes[i].material.transmittance[0], shapes[i].material.transmittance[1], shapes[i].material.transmittance[2]);
|
||||
printf(" material.Ke = (%f, %f ,%f)\n", shapes[i].material.emission[0], shapes[i].material.emission[1], shapes[i].material.emission[2]);
|
||||
printf(" material.Ns = %f\n", shapes[i].material.shininess);
|
||||
printf(" material.map_Ka = %s\n", shapes[i].material.ambient_texname.c_str());
|
||||
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
||||
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
||||
printf(" material.map_Ns = %s\n", shapes[i].material.normal_texname.c_str());
|
||||
std::map<std::string, std::string>::iterator it(shapes[i].material.unknown_parameter.begin());
|
||||
std::map<std::string, std::string>::iterator itEnd(shapes[i].material.unknown_parameter.end());
|
||||
for (; it != itEnd; it++) {
|
||||
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char **argv)
|
||||
{
|
||||
// assert(true == TestLoadObj("cornell_box.obj",true));
|
||||
// assert(true == TestLoadObj("cube.obj",true));
|
||||
assert(true==TestLoadObj("samurai_monastry.obj",false));
|
||||
assert(true==TestLoadObj("teddy2_VHACD_CHs.obj",true));
|
||||
return 0;
|
||||
}
|
||||
23
examples/ThirdPartyLibs/Wavefront/premake4.lua
Normal file
23
examples/ThirdPartyLibs/Wavefront/premake4.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
project "App_WavefrontObjLoader"
|
||||
|
||||
kind "ConsoleApp"
|
||||
|
||||
-- defines { }
|
||||
|
||||
targetdir "../../bin"
|
||||
|
||||
includedirs
|
||||
{
|
||||
".","../../src"
|
||||
}
|
||||
|
||||
|
||||
links { "Bullet3Common" }
|
||||
|
||||
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h"
|
||||
}
|
||||
|
||||
682
examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp
Normal file
682
examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp
Normal file
@@ -0,0 +1,682 @@
|
||||
//
|
||||
// Copyright 2012-2013, Syoyo Fujita.
|
||||
//
|
||||
// Licensed under 2-clause BSD liecense.
|
||||
//
|
||||
|
||||
// Erwin Coumans: improved performance, especially in debug mode on Visual Studio (25sec -> 4sec)
|
||||
//
|
||||
// version 0.9.5: Parse multiple group name.
|
||||
// Add support of specifying the base path to load material file.
|
||||
// version 0.9.4: Initial suupport of group tag(g)
|
||||
// version 0.9.3: Fix parsing triple 'x/y/z'
|
||||
// version 0.9.2: Add more .mtl load support
|
||||
// version 0.9.1: Add initial .mtl load support
|
||||
// version 0.9.0: Initial
|
||||
//
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
namespace tinyobj {
|
||||
|
||||
struct vertex_index {
|
||||
int v_idx, vt_idx, vn_idx, dummy;
|
||||
};
|
||||
struct MyIndices
|
||||
{
|
||||
int m_offset;
|
||||
int m_numIndices;
|
||||
};
|
||||
|
||||
|
||||
// for std::map
|
||||
static inline bool operator<(const vertex_index& a, const vertex_index& b)
|
||||
{
|
||||
if (a.v_idx != b.v_idx) return (a.v_idx < b.v_idx);
|
||||
if (a.vn_idx != b.vn_idx) return (a.vn_idx < b.vn_idx);
|
||||
if (a.vt_idx != b.vt_idx) return (a.vt_idx < b.vt_idx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline bool isSpace(const char c) {
|
||||
return (c == ' ') || (c == '\t');
|
||||
}
|
||||
|
||||
static inline bool isNewLine(const char c) {
|
||||
return (c == '\r') || (c == '\n') || (c == '\0');
|
||||
}
|
||||
|
||||
// Make index zero-base, and also support relative index.
|
||||
static inline int fixIndex(int idx, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (idx > 0) {
|
||||
i = idx - 1;
|
||||
} else if (idx == 0) {
|
||||
i = 0;
|
||||
} else { // negative value = relative
|
||||
i = n + idx;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline std::string parseString(const char*& token)
|
||||
{
|
||||
std::string s;
|
||||
int b = strspn(token, " \t");
|
||||
int e = strcspn(token, " \t\r");
|
||||
s = std::string(&token[b], &token[e]);
|
||||
|
||||
token += (e - b);
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline float parseFloat(const char*& token)
|
||||
{
|
||||
token += strspn(token, " \t");
|
||||
float f = (float)atof(token);
|
||||
token += strcspn(token, " \t\r");
|
||||
return f;
|
||||
}
|
||||
|
||||
static inline void parseFloat2(
|
||||
float& x, float& y,
|
||||
const char*& token)
|
||||
{
|
||||
x = parseFloat(token);
|
||||
y = parseFloat(token);
|
||||
}
|
||||
|
||||
static inline void parseFloat3(
|
||||
float& x, float& y, float& z,
|
||||
const char*& token)
|
||||
{
|
||||
x = parseFloat(token);
|
||||
y = parseFloat(token);
|
||||
z = parseFloat(token);
|
||||
}
|
||||
|
||||
|
||||
// Parse triples: i, i/j/k, i//k, i/j
|
||||
static vertex_index parseTriple(
|
||||
const char* &token,
|
||||
int vsize,
|
||||
int vnsize,
|
||||
int vtsize)
|
||||
{
|
||||
vertex_index vi;
|
||||
vi.vn_idx = -1;
|
||||
vi.vt_idx = -1;
|
||||
vi.v_idx= -1;
|
||||
|
||||
vi.v_idx = fixIndex(atoi(token), vsize);
|
||||
token += strcspn(token, "/ \t\r");
|
||||
if (token[0] != '/') {
|
||||
return vi;
|
||||
}
|
||||
token++;
|
||||
|
||||
// i//k
|
||||
if (token[0] == '/') {
|
||||
token++;
|
||||
vi.vn_idx = fixIndex(atoi(token), vnsize);
|
||||
token += strcspn(token, "/ \t\r");
|
||||
return vi;
|
||||
}
|
||||
|
||||
// i/j/k or i/j
|
||||
vi.vt_idx = fixIndex(atoi(token), vtsize);
|
||||
token += strcspn(token, "/ \t\r");
|
||||
if (token[0] != '/') {
|
||||
return vi;
|
||||
}
|
||||
|
||||
// i/j/k
|
||||
token++; // skip '/'
|
||||
vi.vn_idx = fixIndex(atoi(token), vnsize);
|
||||
token += strcspn(token, "/ \t\r");
|
||||
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() > (3*i.v_idx+2));
|
||||
|
||||
positions.push_back(in_positions[3*i.v_idx+0]);
|
||||
positions.push_back(in_positions[3*i.v_idx+1]);
|
||||
positions.push_back(in_positions[3*i.v_idx+2]);
|
||||
|
||||
if (i.vn_idx >= 0) {
|
||||
normals.push_back(in_normals[3*i.vn_idx+0]);
|
||||
normals.push_back(in_normals[3*i.vn_idx+1]);
|
||||
normals.push_back(in_normals[3*i.vn_idx+2]);
|
||||
}
|
||||
|
||||
if (i.vt_idx >= 0) {
|
||||
texcoords.push_back(in_texcoords[2*i.vt_idx+0]);
|
||||
texcoords.push_back(in_texcoords[2*i.vt_idx+1]);
|
||||
}
|
||||
|
||||
unsigned int idx = positions.size() / 3 - 1;
|
||||
vertexCache[i] = idx;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
exportFaceGroupToShape(
|
||||
shape_t& shape,
|
||||
const std::vector<float>& in_positions,
|
||||
const std::vector<float>& in_normals,
|
||||
const std::vector<float>& in_texcoords,
|
||||
const std::vector<MyIndices >& faceGroup,
|
||||
const material_t material,
|
||||
const std::string name,
|
||||
std::vector<vertex_index>& allIndices
|
||||
)
|
||||
{
|
||||
if (faceGroup.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Flattened version of vertex data
|
||||
std::vector<float> positions;
|
||||
std::vector<float> normals;
|
||||
std::vector<float> texcoords;
|
||||
std::map<vertex_index, unsigned int> vertexCache;
|
||||
std::vector<unsigned int> indices;
|
||||
|
||||
// Flatten vertices and indices
|
||||
for (size_t i = 0; i < faceGroup.size(); i++)
|
||||
{
|
||||
|
||||
const MyIndices& face = faceGroup[i];
|
||||
|
||||
vertex_index i0 = allIndices[face.m_offset];
|
||||
vertex_index i1;
|
||||
i1.vn_idx = -1;
|
||||
i1.vt_idx = -1;
|
||||
i1.v_idx= -1;
|
||||
vertex_index i2 = allIndices[face.m_offset+1];
|
||||
|
||||
size_t npolys = face.m_numIndices;//.size();
|
||||
|
||||
|
||||
{
|
||||
// Polygon -> triangle fan conversion
|
||||
for (size_t k = 2; k < npolys; k++)
|
||||
{
|
||||
i1 = i2;
|
||||
i2 = allIndices[face.m_offset+k];
|
||||
|
||||
unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0);
|
||||
unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1);
|
||||
unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2);
|
||||
|
||||
indices.push_back(v0);
|
||||
indices.push_back(v1);
|
||||
indices.push_back(v2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Construct shape.
|
||||
//
|
||||
shape.name = name;
|
||||
shape.mesh.positions.swap(positions);
|
||||
shape.mesh.normals.swap(normals);
|
||||
shape.mesh.texcoords.swap(texcoords);
|
||||
shape.mesh.indices.swap(indices);
|
||||
|
||||
shape.material = material;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void InitMaterial(material_t& material) {
|
||||
material.name = "";
|
||||
material.ambient_texname = "";
|
||||
material.diffuse_texname = "";
|
||||
material.specular_texname = "";
|
||||
material.normal_texname = "";
|
||||
for (int i = 0; i < 3; i ++) {
|
||||
material.ambient[i] = 0.f;
|
||||
material.diffuse[i] = 0.f;
|
||||
material.specular[i] = 0.f;
|
||||
material.transmittance[i] = 0.f;
|
||||
material.emission[i] = 0.f;
|
||||
}
|
||||
material.shininess = 1.f;
|
||||
}
|
||||
|
||||
std::string LoadMtl (
|
||||
std::map<std::string, material_t>& material_map,
|
||||
const char* filename,
|
||||
const char* mtl_basepath)
|
||||
{
|
||||
material_map.clear();
|
||||
std::stringstream err;
|
||||
|
||||
std::string filepath;
|
||||
|
||||
if (mtl_basepath) {
|
||||
filepath = std::string(mtl_basepath) + std::string(filename);
|
||||
} else {
|
||||
filepath = std::string(filename);
|
||||
}
|
||||
|
||||
std::ifstream ifs(filepath.c_str());
|
||||
if (!ifs) {
|
||||
err << "Cannot open file [" << filepath << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
|
||||
material_t material;
|
||||
|
||||
int maxchars = 8192; // Alloc enough size.
|
||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||
while (ifs.peek() != -1) {
|
||||
ifs.getline(&buf[0], maxchars);
|
||||
|
||||
std::string linebuf(&buf[0]);
|
||||
|
||||
// Trim newline '\r\n' or '\r'
|
||||
if (linebuf.size() > 0) {
|
||||
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1);
|
||||
}
|
||||
if (linebuf.size() > 0) {
|
||||
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1);
|
||||
}
|
||||
|
||||
// Skip if empty line.
|
||||
if (linebuf.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip leading space.
|
||||
const char* token = linebuf.c_str();
|
||||
token += strspn(token, " \t");
|
||||
|
||||
assert(token);
|
||||
if (token[0] == '\0') continue; // empty line
|
||||
|
||||
if (token[0] == '#') continue; // comment line
|
||||
|
||||
// new mtl
|
||||
if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) {
|
||||
// flush previous material.
|
||||
material_map.insert(std::pair<std::string, material_t>(material.name, material));
|
||||
|
||||
// initial temporary material
|
||||
InitMaterial(material);
|
||||
|
||||
// set new mtl name
|
||||
char namebuf[4096];
|
||||
token += 7;
|
||||
sscanf(token, "%s", namebuf);
|
||||
material.name = namebuf;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ambient
|
||||
if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(r, g, b, token);
|
||||
material.ambient[0] = r;
|
||||
material.ambient[1] = g;
|
||||
material.ambient[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// diffuse
|
||||
if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(r, g, b, token);
|
||||
material.diffuse[0] = r;
|
||||
material.diffuse[1] = g;
|
||||
material.diffuse[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// specular
|
||||
if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(r, g, b, token);
|
||||
material.specular[0] = r;
|
||||
material.specular[1] = g;
|
||||
material.specular[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// specular
|
||||
if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(r, g, b, token);
|
||||
material.specular[0] = r;
|
||||
material.specular[1] = g;
|
||||
material.specular[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// emission
|
||||
if(token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) {
|
||||
token += 2;
|
||||
float r, g, b;
|
||||
parseFloat3(r, g, b, token);
|
||||
material.emission[0] = r;
|
||||
material.emission[1] = g;
|
||||
material.emission[2] = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// shininess
|
||||
if(token[0] == 'N' && token[1] == 's' && isSpace(token[2])) {
|
||||
token += 2;
|
||||
material.shininess = parseFloat(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ambient texture
|
||||
if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) {
|
||||
token += 7;
|
||||
material.ambient_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// diffuse texture
|
||||
if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) {
|
||||
token += 7;
|
||||
material.diffuse_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// specular texture
|
||||
if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) {
|
||||
token += 7;
|
||||
material.specular_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal texture
|
||||
if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) {
|
||||
token += 7;
|
||||
material.normal_texname = token;
|
||||
continue;
|
||||
}
|
||||
|
||||
// unknown parameter
|
||||
const char* _space = strchr(token, ' ');
|
||||
if(!_space) {
|
||||
_space = strchr(token, '\t');
|
||||
}
|
||||
if(_space) {
|
||||
int len = _space - token;
|
||||
std::string key(token, len);
|
||||
std::string value = _space + 1;
|
||||
material.unknown_parameter.insert(std::pair<std::string, std::string>(key, value));
|
||||
}
|
||||
}
|
||||
// flush last material.
|
||||
material_map.insert(std::pair<std::string, material_t>(material.name, material));
|
||||
|
||||
return err.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
LoadObj(
|
||||
std::vector<shape_t>& shapes,
|
||||
const char* filename,
|
||||
const char* mtl_basepath)
|
||||
{
|
||||
|
||||
shapes.resize(0);
|
||||
std::vector<vertex_index> allIndices;
|
||||
allIndices.reserve(1024*1024);
|
||||
|
||||
MyIndices face;
|
||||
|
||||
std::stringstream err;
|
||||
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs) {
|
||||
err << "Cannot open file [" << filename << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
|
||||
std::vector<float> v;
|
||||
v.reserve(1024*1024);
|
||||
std::vector<float> vn;
|
||||
vn.reserve(1024*1024);
|
||||
std::vector<float> vt;
|
||||
vt.reserve(1024*1024);
|
||||
//std::vector<std::vector<vertex_index> > faceGroup;
|
||||
std::vector<MyIndices> faceGroup;
|
||||
faceGroup.reserve(1024*1024);
|
||||
std::string name;
|
||||
|
||||
// material
|
||||
std::map<std::string, material_t> material_map;
|
||||
material_t material;
|
||||
|
||||
int maxchars = 8192; // Alloc enough size.
|
||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||
while (ifs.peek() != -1) {
|
||||
ifs.getline(&buf[0], maxchars);
|
||||
|
||||
std::string linebuf(&buf[0]);
|
||||
|
||||
// Trim newline '\r\n' or '\r'
|
||||
if (linebuf.size() > 0) {
|
||||
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1);
|
||||
}
|
||||
if (linebuf.size() > 0) {
|
||||
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1);
|
||||
}
|
||||
|
||||
// Skip if empty line.
|
||||
if (linebuf.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip leading space.
|
||||
const char* token = linebuf.c_str();
|
||||
token += strspn(token, " \t");
|
||||
|
||||
assert(token);
|
||||
if (token[0] == '\0') continue; // empty line
|
||||
|
||||
if (token[0] == '#') continue; // comment line
|
||||
|
||||
// vertex
|
||||
if (token[0] == 'v' && isSpace((token[1]))) {
|
||||
token += 2;
|
||||
float x, y, z;
|
||||
parseFloat3(x, y, z, token);
|
||||
v.push_back(x);
|
||||
v.push_back(y);
|
||||
v.push_back(z);
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal
|
||||
if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) {
|
||||
token += 3;
|
||||
float x, y, z;
|
||||
parseFloat3(x, y, z, token);
|
||||
vn.push_back(x);
|
||||
vn.push_back(y);
|
||||
vn.push_back(z);
|
||||
continue;
|
||||
}
|
||||
|
||||
// texcoord
|
||||
if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) {
|
||||
token += 3;
|
||||
float x, y;
|
||||
parseFloat2(x, y, token);
|
||||
vt.push_back(x);
|
||||
vt.push_back(y);
|
||||
continue;
|
||||
}
|
||||
|
||||
// face
|
||||
if (token[0] == 'f' && isSpace((token[1]))) {
|
||||
token += 2;
|
||||
token += strspn(token, " \t");
|
||||
|
||||
face.m_offset = allIndices.size();
|
||||
face.m_numIndices = 0;
|
||||
|
||||
while (!isNewLine(token[0])) {
|
||||
vertex_index vi = parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2);
|
||||
allIndices.push_back(vi);
|
||||
face.m_numIndices++;
|
||||
int n = strspn(token, " \t\r");
|
||||
token += n;
|
||||
}
|
||||
|
||||
faceGroup.push_back(face);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// use mtl
|
||||
if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) {
|
||||
|
||||
char namebuf[4096];
|
||||
token += 7;
|
||||
sscanf(token, "%s", namebuf);
|
||||
|
||||
if (material_map.find(namebuf) != material_map.end()) {
|
||||
material = material_map[namebuf];
|
||||
} else {
|
||||
// { error!! material not found }
|
||||
InitMaterial(material);
|
||||
}
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// load mtl
|
||||
if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) {
|
||||
char namebuf[4096];
|
||||
token += 7;
|
||||
sscanf(token, "%s", namebuf);
|
||||
|
||||
std::string err_mtl = LoadMtl(material_map, namebuf, mtl_basepath);
|
||||
if (!err_mtl.empty()) {
|
||||
faceGroup.resize(0); // for safety
|
||||
return err_mtl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// group name
|
||||
if (token[0] == 'g' && isSpace((token[1]))) {
|
||||
|
||||
// flush previous face group.
|
||||
shape_t shape;
|
||||
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name,allIndices);
|
||||
if (ret) {
|
||||
shapes.push_back(shape);
|
||||
}
|
||||
|
||||
faceGroup.resize(0);
|
||||
|
||||
std::vector<std::string> names;
|
||||
while (!isNewLine(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 skipt 0th element.
|
||||
if (names.size() > 1) {
|
||||
name = names[1];
|
||||
} else {
|
||||
name = "";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// object name
|
||||
if (token[0] == 'o' && isSpace((token[1]))) {
|
||||
|
||||
// flush previous face group.
|
||||
shape_t shape;
|
||||
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name,allIndices);
|
||||
if (ret) {
|
||||
shapes.push_back(shape);
|
||||
}
|
||||
|
||||
faceGroup.resize(0);
|
||||
|
||||
// @todo { multiple object name? }
|
||||
char namebuf[4096];
|
||||
token += 2;
|
||||
sscanf(token, "%s", namebuf);
|
||||
name = std::string(namebuf);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore unknown command.
|
||||
}
|
||||
|
||||
shape_t shape;
|
||||
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name,allIndices);
|
||||
if (ret) {
|
||||
shapes.push_back(shape);
|
||||
}
|
||||
faceGroup.resize(0); // for safety
|
||||
|
||||
return err.str();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
60
examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h
Normal file
60
examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// Copyright 2012-2013, Syoyo Fujita.
|
||||
//
|
||||
// Licensed under 2-clause BSD liecense.
|
||||
//
|
||||
#ifndef _TINY_OBJ_LOADER_H
|
||||
#define _TINY_OBJ_LOADER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace tinyobj {
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string name;
|
||||
|
||||
float ambient[3];
|
||||
float diffuse[3];
|
||||
float specular[3];
|
||||
float transmittance[3];
|
||||
float emission[3];
|
||||
float shininess;
|
||||
|
||||
std::string ambient_texname;
|
||||
std::string diffuse_texname;
|
||||
std::string specular_texname;
|
||||
std::string normal_texname;
|
||||
std::map<std::string, std::string> unknown_parameter;
|
||||
} material_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::vector<float> positions;
|
||||
std::vector<float> normals;
|
||||
std::vector<float> texcoords;
|
||||
std::vector<unsigned int> indices;
|
||||
} mesh_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string name;
|
||||
material_t material;
|
||||
mesh_t mesh;
|
||||
} shape_t;
|
||||
|
||||
/// Loads .obj from a file.
|
||||
/// 'shapes' will be filled with parsed shape data
|
||||
/// The function returns error string.
|
||||
/// Returns empty string when loading .obj success.
|
||||
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
|
||||
std::string LoadObj(
|
||||
std::vector<shape_t>& shapes, // [output]
|
||||
const char* filename,
|
||||
const char* mtl_basepath = NULL);
|
||||
|
||||
};
|
||||
|
||||
#endif // _TINY_OBJ_LOADER_H
|
||||
Reference in New Issue
Block a user