mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-15 00:24:40 +00:00
* Adjustment: Update Bullet version to 3.24.
This commit is contained in:
parent
35de012ee7
commit
4a3f31df2a
6148 changed files with 2112532 additions and 56873 deletions
|
|
@ -0,0 +1,3 @@
|
|||
// Copyright 2012-2013, Syoyo Fujita.
|
||||
//
|
||||
// Licensed under 2-clause BSD liecense.
|
||||
139
Engine/lib/bullet/examples/ThirdPartyLibs/Wavefront/README.md
Normal file
139
Engine/lib/bullet/examples/ThirdPartyLibs/Wavefront/README.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
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
|
||||
-----
|
||||
Data format
|
||||
attrib_t contains single and linear array of vertex data(position, normal and texcoord).
|
||||
|
||||
attrib_t::vertices => 3 floats per vertex
|
||||
|
||||
v[0] v[1] v[2] v[3] v[n-1]
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
| x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
|
||||
attrib_t::normals => 3 floats per vertex
|
||||
|
||||
n[0] n[1] n[2] n[3] n[n-1]
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
| x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
|
||||
attrib_t::texcoords => 2 floats per vertex
|
||||
|
||||
t[0] t[1] t[2] t[3] t[n-1]
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
| u | v | u | v | u | v | u | v | .... | u | v |
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
|
||||
attrib_t::colors => 3 floats per vertex(vertex color. optional)
|
||||
|
||||
c[0] c[1] c[2] c[3] c[n-1]
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
| x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
|
||||
+-----------+-----------+-----------+-----------+ +-----------+
|
||||
|
||||
Each shape_t::mesh_t does not contain vertex data but contains array index to attrib_t. See loader_example.cc for more details.
|
||||
|
||||
|
||||
mesh_t::indices => array of vertex indices.
|
||||
|
||||
+----+----+----+----+----+----+----+----+----+----+ +--------+
|
||||
| i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-1) |
|
||||
+----+----+----+----+----+----+----+----+----+----+ +--------+
|
||||
|
||||
Each index has an array index to attrib_t::vertices, attrib_t::normals and attrib_t::texcoords.
|
||||
|
||||
mesh_t::num_face_vertices => array of the number of vertices per face(e.g. 3 = triangle, 4 = quad , 5 or more = N-gons).
|
||||
|
||||
|
||||
+---+---+---+ +---+
|
||||
| 3 | 4 | 3 | ...... | 3 |
|
||||
+---+---+---+ +---+
|
||||
| | | |
|
||||
| | | +-----------------------------------------+
|
||||
| | | |
|
||||
| | +------------------------------+ |
|
||||
| | | |
|
||||
| +------------------+ | |
|
||||
| | | |
|
||||
|/ |/ |/ |/
|
||||
|
||||
mesh_t::indices
|
||||
|
||||
| face[0] | face[1] | face[2] | | face[n-1] |
|
||||
+----+----+----+----+----+----+----+----+----+----+ +--------+--------+--------+
|
||||
| i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-3) | i(n-2) | i(n-1) |
|
||||
+----+----+----+----+----+----+----+----+----+----+ +--------+--------+--------+
|
||||
|
||||
```c++
|
||||
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
std::string inputfile = "cornell_box.obj";
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
|
||||
LoadObj(attrib, shapes, inputfile.c_str());
|
||||
|
||||
// Loop over shapes
|
||||
for (size_t s = 0; s < shapes.size(); s++) {
|
||||
// Loop over faces(polygon)
|
||||
size_t index_offset = 0;
|
||||
for (size_t f = 0; f < shapes[s].mesh.indices.size(); f++) {
|
||||
int fv = 3;
|
||||
// Loop over vertices in the face.
|
||||
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 tx = attrib.texcoords[2*idx.texcoord_index+0];
|
||||
tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1];
|
||||
}
|
||||
index_offset += fv;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
105
Engine/lib/bullet/examples/ThirdPartyLibs/Wavefront/main.cpp
Normal file
105
Engine/lib/bullet/examples/ThirdPartyLibs/Wavefront/main.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#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<bt_tinyobj::shape_t> shapes;
|
||||
std::string err = bt_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;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
project "App_WavefrontObjLoader"
|
||||
|
||||
kind "ConsoleApp"
|
||||
|
||||
-- defines { }
|
||||
|
||||
targetdir "../../bin"
|
||||
|
||||
includedirs
|
||||
{
|
||||
".","../../src"
|
||||
}
|
||||
|
||||
|
||||
links { "Bullet3Common" }
|
||||
|
||||
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h"
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,883 @@
|
|||
//
|
||||
// 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>
|
||||
#ifdef USE_STREAM
|
||||
#include <fstream>
|
||||
#else
|
||||
#include "../../CommonInterfaces/CommonFileIOInterface.h"
|
||||
#endif
|
||||
#include <sstream>
|
||||
#include "tiny_obj_loader.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace bt_tinyobj
|
||||
{
|
||||
#ifdef USE_STREAM
|
||||
//See http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
|
||||
std::istream& safeGetline(std::istream& is, std::string& t)
|
||||
{
|
||||
t.clear();
|
||||
|
||||
// The characters in the stream are read one-by-one using a std::streambuf.
|
||||
// That is faster than reading them one-by-one using the std::istream.
|
||||
// Code that uses streambuf this way must be guarded by a sentry object.
|
||||
// The sentry object performs various tasks,
|
||||
// such as thread synchronization and updating the stream state.
|
||||
|
||||
std::istream::sentry se(is, true);
|
||||
std::streambuf* sb = is.rdbuf();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int c = sb->sbumpc();
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
return is;
|
||||
case '\r':
|
||||
if (sb->sgetc() == '\n')
|
||||
sb->sbumpc();
|
||||
return is;
|
||||
case EOF:
|
||||
// Also handle the case when the last line has no line ending
|
||||
if (t.empty())
|
||||
is.setstate(std::ios::eofbit);
|
||||
return is;
|
||||
default:
|
||||
t += (char)c;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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 bool fixIndex(int idx, int n, int* ret)
|
||||
{
|
||||
if (!ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idx > 0)
|
||||
{
|
||||
(*ret) = idx - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (idx == 0)
|
||||
{
|
||||
// zero is not allowed according to the spec.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idx < 0)
|
||||
{
|
||||
(*ret) = n + idx; // negative value = relative
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // never reach here.
|
||||
}
|
||||
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 with index offsets: i, i/j/k, i//k, i/j
|
||||
static bool parseTriple(const char** token, int vsize, int vnsize, int vtsize,
|
||||
vertex_index_t* ret)
|
||||
{
|
||||
if (!ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vertex_index_t vi(-1);
|
||||
|
||||
if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
if ((*token)[0] != '/')
|
||||
{
|
||||
(*ret) = vi;
|
||||
return true;
|
||||
}
|
||||
(*token)++;
|
||||
|
||||
// i//k
|
||||
if ((*token)[0] == '/')
|
||||
{
|
||||
(*token)++;
|
||||
if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
(*ret) = vi;
|
||||
return true;
|
||||
}
|
||||
|
||||
// i/j/k or i/j
|
||||
if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
if ((*token)[0] != '/')
|
||||
{
|
||||
(*ret) = vi;
|
||||
return true;
|
||||
}
|
||||
|
||||
// i/j/k
|
||||
(*token)++; // skip '/'
|
||||
if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
(*token) += strcspn((*token), "/ \t\r");
|
||||
|
||||
(*ret) = vi;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool exportFaceGroupToShape(shape_t* shape, const std::vector<face_t>& face_group,
|
||||
const material_t material, const std::string& name,
|
||||
const std::vector<float>& v)
|
||||
{
|
||||
if (face_group.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
shape->name = name;
|
||||
// Flattened version of vertex data
|
||||
|
||||
// Flatten vertices and indices
|
||||
for (size_t i = 0; i < face_group.size(); i++)
|
||||
{
|
||||
const face_t& face = face_group[i];
|
||||
size_t npolys = face.size();
|
||||
|
||||
if (npolys < 3)
|
||||
{
|
||||
// Face must have 3+ vertices.
|
||||
continue;
|
||||
}
|
||||
vertex_index_t i0 = face[0];
|
||||
vertex_index_t i1(-1);
|
||||
vertex_index_t i2 = face[1];
|
||||
|
||||
face_t remainingFace = face; // copy
|
||||
size_t guess_vert = 0;
|
||||
vertex_index_t ind[3];
|
||||
|
||||
// How many iterations can we do without decreasing the remaining
|
||||
// vertices.
|
||||
size_t remainingIterations = face.size();
|
||||
size_t previousRemainingVertices = remainingFace.size();
|
||||
|
||||
while (remainingFace.size() > 3 && remainingIterations > 0)
|
||||
{
|
||||
npolys = remainingFace.size();
|
||||
if (guess_vert >= npolys)
|
||||
{
|
||||
guess_vert -= npolys;
|
||||
}
|
||||
|
||||
if (previousRemainingVertices != npolys)
|
||||
{
|
||||
// The number of remaining vertices decreased. Reset counters.
|
||||
previousRemainingVertices = npolys;
|
||||
remainingIterations = npolys;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We didn't consume a vertex on previous iteration, reduce the
|
||||
// available iterations.
|
||||
remainingIterations--;
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < 3; k++)
|
||||
{
|
||||
ind[k] = remainingFace[(guess_vert + k) % npolys];
|
||||
size_t vi = size_t(ind[k].v_idx);
|
||||
}
|
||||
// this triangle is an ear
|
||||
{
|
||||
index_t idx0, idx1, idx2;
|
||||
idx0.vertex_index = ind[0].v_idx;
|
||||
idx0.normal_index = ind[0].vn_idx;
|
||||
idx0.texcoord_index = ind[0].vt_idx;
|
||||
idx1.vertex_index = ind[1].v_idx;
|
||||
idx1.normal_index = ind[1].vn_idx;
|
||||
idx1.texcoord_index = ind[1].vt_idx;
|
||||
idx2.vertex_index = ind[2].v_idx;
|
||||
idx2.normal_index = ind[2].vn_idx;
|
||||
idx2.texcoord_index = ind[2].vt_idx;
|
||||
|
||||
shape->mesh.indices.push_back(idx0);
|
||||
shape->mesh.indices.push_back(idx1);
|
||||
shape->mesh.indices.push_back(idx2);
|
||||
}
|
||||
|
||||
// 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->material = material;
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitMaterial(material_t& material)
|
||||
{
|
||||
material.name = "";
|
||||
material.ambient_texname = "";
|
||||
material.diffuse_texname = "";
|
||||
material.specular_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;
|
||||
material.transparency = 1.f;
|
||||
}
|
||||
|
||||
std::string LoadMtl(
|
||||
std::map<std::string, material_t>& material_map,
|
||||
const char* filename,
|
||||
const char* mtl_basepath,
|
||||
CommonFileIOInterface* fileIO)
|
||||
{
|
||||
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);
|
||||
}
|
||||
#ifdef USE_STREAM
|
||||
std::ifstream ifs(filepath.c_str());
|
||||
if (!ifs)
|
||||
{
|
||||
err << "Cannot open file [" << filepath << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
#else
|
||||
int fileHandle = fileIO->fileOpen(filepath.c_str(), "r");
|
||||
if (fileHandle < 0)
|
||||
{
|
||||
err << "Cannot open file [" << filepath << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
material_t material;
|
||||
|
||||
int maxchars = 8192; // Alloc enough size.
|
||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||
#ifdef USE_STREAM
|
||||
while (ifs.peek() != -1)
|
||||
#else
|
||||
char* line = 0;
|
||||
do
|
||||
#endif
|
||||
{
|
||||
std::string linebuf;
|
||||
#ifdef USE_STREAM
|
||||
safeGetline(ifs, linebuf);
|
||||
#else
|
||||
char tmpBuf[1024];
|
||||
line = fileIO->readLine(fileHandle, tmpBuf, 1024);
|
||||
if (line)
|
||||
{
|
||||
linebuf = line;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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] == '\r') linebuf.erase(linebuf.size() - 1);
|
||||
}
|
||||
|
||||
// Skip if empty line.
|
||||
if (linebuf.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// transparency
|
||||
if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2]))
|
||||
{
|
||||
token += 2;
|
||||
material.transparency = parseFloat(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
// transparency
|
||||
if (token[0] == 'd' && isSpace(token[1]))
|
||||
{
|
||||
token += 1;
|
||||
material.transparency = 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));
|
||||
}
|
||||
}
|
||||
#ifndef USE_STREAM
|
||||
while (line)
|
||||
;
|
||||
#endif
|
||||
// flush last material.
|
||||
material_map.insert(std::pair<std::string, material_t>(material.name, material));
|
||||
|
||||
if (fileHandle >= 0)
|
||||
{
|
||||
fileIO->fileClose(fileHandle);
|
||||
}
|
||||
return err.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
LoadObj(
|
||||
attrib_t& attrib,
|
||||
std::vector<shape_t>& shapes,
|
||||
const char* filename,
|
||||
const char* mtl_basepath,
|
||||
CommonFileIOInterface* fileIO)
|
||||
{
|
||||
attrib.vertices.clear();
|
||||
attrib.normals.clear();
|
||||
attrib.texcoords.clear();
|
||||
shapes.clear();
|
||||
std::string tmp = filename;
|
||||
if (!mtl_basepath)
|
||||
{
|
||||
int last_slash = 0;
|
||||
for (int c = 0; c < (int)tmp.size(); ++c)
|
||||
if (tmp[c] == '/' || tmp[c] == '\\')
|
||||
last_slash = c;
|
||||
tmp = tmp.substr(0, last_slash);
|
||||
mtl_basepath = tmp.c_str();
|
||||
//fprintf(stderr, "MTL PATH '%s' orig '%s'\n", mtl_basepath, filename);
|
||||
}
|
||||
std::stringstream err;
|
||||
#ifdef USE_STREAM
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs)
|
||||
{
|
||||
err << "Cannot open file [" << filename << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
#else
|
||||
int fileHandle = fileIO->fileOpen(filename, "r");
|
||||
if (fileHandle < 0)
|
||||
{
|
||||
err << "Cannot open file [" << filename << "]" << std::endl;
|
||||
return err.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<float> v;
|
||||
std::vector<float> vn;
|
||||
std::vector<float> vt;
|
||||
std::string name;
|
||||
|
||||
int greatest_v_idx = -1;
|
||||
int greatest_vn_idx = -1;
|
||||
int greatest_vt_idx = -1;
|
||||
|
||||
std::vector<face_t> faceGroup;
|
||||
// material
|
||||
std::map<std::string, material_t> material_map;
|
||||
material_t material;
|
||||
InitMaterial(material);
|
||||
|
||||
int maxchars = 8192; // Alloc enough size.
|
||||
std::vector<char> buf(maxchars); // Alloc enough size.
|
||||
std::string linebuf;
|
||||
linebuf.reserve(maxchars);
|
||||
|
||||
#ifdef USE_STREAM
|
||||
while (ifs.peek() != -1)
|
||||
#else
|
||||
char* line = 0;
|
||||
do
|
||||
#endif
|
||||
{
|
||||
linebuf.resize(0);
|
||||
#ifdef USE_STREAM
|
||||
safeGetline(ifs, linebuf);
|
||||
#else
|
||||
char tmpBuf[1024];
|
||||
line = fileIO->readLine(fileHandle, tmpBuf, 1024);
|
||||
if (line)
|
||||
{
|
||||
linebuf = line;
|
||||
}
|
||||
#endif
|
||||
// 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_t face;
|
||||
|
||||
face.reserve(3);
|
||||
|
||||
while (!isNewLine(token[0]))
|
||||
{
|
||||
vertex_index_t vi;
|
||||
if (!parseTriple(&token, static_cast<int>(v.size() / 3),
|
||||
static_cast<int>(vn.size() / 3),
|
||||
static_cast<int>(vt.size() / 2), &vi))
|
||||
{
|
||||
err << "Failed parse `f' line(e.g. zero value for face index.";
|
||||
return err.str();
|
||||
}
|
||||
|
||||
greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx;
|
||||
greatest_vn_idx =
|
||||
greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx;
|
||||
greatest_vt_idx =
|
||||
greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx;
|
||||
|
||||
face.push_back(vi);
|
||||
size_t 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, fileIO);
|
||||
if (!err_mtl.empty())
|
||||
{
|
||||
//face_group.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, faceGroup, material, name, v);
|
||||
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, faceGroup, material, name, v);
|
||||
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.
|
||||
}
|
||||
#ifndef USE_STREAM
|
||||
while (line)
|
||||
;
|
||||
#endif
|
||||
|
||||
shape_t shape;
|
||||
bool ret = exportFaceGroupToShape(&shape, faceGroup, material, name, v);
|
||||
if (ret)
|
||||
{
|
||||
shapes.push_back(shape);
|
||||
}
|
||||
faceGroup.resize(0); // for safety
|
||||
|
||||
attrib.vertices.swap(v);
|
||||
attrib.normals.swap(vn);
|
||||
attrib.texcoords.swap(vt);
|
||||
|
||||
if (fileHandle >= 0)
|
||||
{
|
||||
fileIO->fileClose(fileHandle);
|
||||
}
|
||||
return err.str();
|
||||
}
|
||||
|
||||
}; // namespace bt_tinyobj
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// Copyright 2012-2013, Syoyo Fujita.
|
||||
//
|
||||
// Licensed under 2-clause BSD liecense.
|
||||
//
|
||||
#ifndef _BT_TINY_OBJ_LOADER_H
|
||||
#define _BT_TINY_OBJ_LOADER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
struct CommonFileIOInterface;
|
||||
|
||||
namespace bt_tinyobj
|
||||
{
|
||||
struct vertex_index_t
|
||||
{
|
||||
int v_idx, vt_idx, vn_idx;
|
||||
vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
|
||||
explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
|
||||
vertex_index_t(int vidx, int vtidx, int vnidx)
|
||||
: v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
|
||||
};
|
||||
|
||||
typedef std::vector<vertex_index_t> face_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string name;
|
||||
|
||||
float ambient[3];
|
||||
float diffuse[3];
|
||||
float specular[3];
|
||||
float transmittance[3];
|
||||
float emission[3];
|
||||
float shininess;
|
||||
float transparency; // 1 == opaque; 0 == fully transparent
|
||||
|
||||
std::string ambient_texname; // map_Ka
|
||||
std::string diffuse_texname; // map_Kd
|
||||
std::string specular_texname; // map_Ks
|
||||
std::string normal_texname;
|
||||
std::map<std::string, std::string> unknown_parameter;
|
||||
} material_t;
|
||||
|
||||
// Index struct to support different indices for vtx/normal/texcoord.
|
||||
// -1 means not used.
|
||||
typedef struct
|
||||
{
|
||||
int vertex_index;
|
||||
int normal_index;
|
||||
int texcoord_index;
|
||||
} index_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::vector<index_t> indices;
|
||||
} mesh_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string name;
|
||||
material_t material;
|
||||
mesh_t mesh;
|
||||
} shape_t;
|
||||
|
||||
// Vertex attributes
|
||||
struct attrib_t
|
||||
{
|
||||
std::vector<float> vertices; // 'v'(xyz)
|
||||
std::vector<float> normals; // 'vn'
|
||||
std::vector<float> texcoords; // 'vt'(uv)
|
||||
attrib_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.
|
||||
#ifdef USE_STREAM
|
||||
std::string LoadObj(
|
||||
attrib_t& attrib,
|
||||
std::vector<shape_t>& shapes, // [output]
|
||||
const char* filename,
|
||||
const char* mtl_basepath = NULL);
|
||||
#else
|
||||
std::string
|
||||
LoadObj(
|
||||
attrib_t& attrib,
|
||||
std::vector<shape_t>& shapes,
|
||||
const char* filename,
|
||||
const char* mtl_basepath,
|
||||
CommonFileIOInterface* fileIO);
|
||||
#endif
|
||||
|
||||
}; // namespace bt_tinyobj
|
||||
|
||||
#endif // _BT_TINY_OBJ_LOADER_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue