67 Commits

Author SHA1 Message Date
Syoyo Fujita
47aad5a129 Merge branch 'normal-texcoord-indices' of github.com:syoyo/tinyobjloader into normal-texcoord-indices
Conflicts:
	tiny_obj_loader.cc
2015-06-24 21:50:23 +09:00
Syoyo Fujita
8b86d6383c Add indices for texcoord and normal. 2015-06-24 21:49:38 +09:00
Syoyo Fujita
e568dd11f7 Add indices for texcoord and normal. 2015-06-24 14:22:52 +09:00
Syoyo Fujita
3058419d7d Update README. Add bugfix notes. 2015-06-23 16:18:29 +09:00
Syoyo Fujita
6727aeaca1 Merge pull request #44 from obviousengineering/oe
Fix groups being ignored if they have 'usemtl' just before 'g'
2015-06-23 16:14:59 +09:00
Ricardo Sánchez-Sáez
fb361547e5 Fix groups being ignored if they have 'usemtl' just before 'g' 2015-06-22 16:14:16 +01:00
Syoyo Fujita
805bd814fa Invert 'Tr'. Fixes #43. 2015-06-20 19:41:41 +09:00
Syoyo Fujita
1adfc794ae Fix sscanf_s seg fault on windows. Fixes #41 2015-06-09 23:49:52 +09:00
Syoyo Fujita
a2851fdf17 Add more links to project using tinyobjloader. 2015-06-08 14:18:35 +09:00
Syoyo Fujita
4e9e812b09 Add Appveyor batch. 2015-06-04 00:06:56 +09:00
Syoyo Fujita
b963227246 Merge branch 'master' of github.com:syoyo/tinyobjloader 2015-06-04 00:02:17 +09:00
Syoyo Fujita
a7759a740a Add Appveyor settings. 2015-06-04 00:01:51 +09:00
Syoyo Fujita
2c005ddad1 Merge pull request #40 from MutterOberin/master
Changed pow function to use double overload
2015-06-02 17:46:38 +09:00
MutterOberin
42d6bfbafb Changed pow function to use double overload 2015-06-01 16:39:36 +02:00
Syoyo Fujita
59acd32d0a Merge pull request #38 from OpenSpace/master
Fix compile warnings under VS 2013 /W4 warning level
2015-05-24 22:19:13 +09:00
Alexander Bock
0aab63eb20 Fixing ptrdiff_t compile error 2015-05-23 22:15:23 +02:00
Alexander Bock
49e82e2e00 Fix compile warnings under VS 2013 /W4 warning level 2015-05-23 22:13:00 +02:00
Syoyo Fujita
7a3e607898 Merge pull request #37 from OpenSpace/master
Add CMake options
2015-05-22 13:37:23 +09:00
Alexander Bock
d828e7521d Add CMake options to toggle the TestLoader application and OBJ Sticher application so that including the project has a smaller footprint 2015-05-21 22:22:59 +02:00
Syoyo Fujita
911f0dd636 Merge pull request #36 from Twinklebear/master
Add support for referencing multiple mtllibs
2015-05-02 15:27:52 +09:00
Will Usher
527000abd6 Add support for referencing multiple mtllibs 2015-05-01 17:32:25 -06:00
Syoyo Fujita
ba5fde9fd5 Remove #28 TODO. 2015-03-03 13:22:56 +09:00
Syoyo Fujita
8b8435d436 Merge branch 'skurmedel-master' 2015-03-03 13:17:28 +09:00
Syoyo Fujita
8d300917a3 Update README.
Bump version 0.9.9.
2015-03-03 13:16:56 +09:00
Syoyo Fujita
79af31df5a Merge branch 'master' of https://github.com/skurmedel/tinyobjloader into skurmedel-master 2015-03-03 12:16:38 +09:00
Syoyo Fujita
e8ed70b15f Merge pull request #33 from expipiplus1/fix-typo
Fix a small typo
2015-03-03 12:13:15 +09:00
Simon Otter
5615af5316 Removed stray parser test file. 2015-03-03 01:39:38 +01:00
Simon Otter
4ea1cf0b77 Implemented a parser and updated tiny_obj_loader.cc to use it unless a define is set. 2015-03-03 01:37:28 +01:00
Joe Hermaszewski
9d7012673e Fix a small typo 2015-02-27 19:58:43 +00:00
Syoyo Fujita
daaec1c9aa Small update. 2015-02-28 01:09:18 +09:00
Syoyo Fujita
28005f9cdf Update copyright year. 2015-02-28 00:47:13 +09:00
Syoyo Fujita
32dcf7d535 Use syoyo/ubu-dev image. 2015-02-27 15:54:04 +09:00
Syoyo Fujita
8a384a057b Update drone.yml 2015-02-27 12:45:44 +09:00
Syoyo Fujita
32414c27b4 Update TODO. 2015-02-27 12:07:02 +09:00
Simon Otter
f020169c26 Created a bunch of tests for the parser, and a spec. 2015-02-23 23:34:16 +01:00
Syoyo Fujita
f0fdaa307d slight change to fixIndex 2015-02-18 12:48:50 +09:00
Syoyo Fujita
743cfcd861 Merge branch 'CoolerExtreme-patch-1' 2015-02-18 12:45:42 +09:00
Syoyo Fujita
285f5b0cfd Merge branch 'patch-1' of https://github.com/CoolerExtreme/tinyobjloader into CoolerExtreme-patch-1
Conflicts:
	tiny_obj_loader.cc
2015-02-18 12:45:34 +09:00
Syoyo Fujita
2cceb53214 Update drone.yml. 2015-02-16 00:47:23 +09:00
Syoyo Fujita
1390f7f707 Fix compilation. 2015-02-15 17:05:57 +09:00
Syoyo Fujita
9979275835 Format source code. 2015-02-15 16:51:38 +09:00
CoolerExtreme
011e1b3ebd Slight typo 2015-02-13 06:37:37 +05:30
CoolerExtreme
f28d2eef88 Fix parseString ? and slight change to fixIndex
function parseString seemed to not increment token after it used strspn to get the length of the whitespace characters at the beginning of token. So strcspn called right after that would return 0 and the created string would be an empty string.

Seems to have been working so far since it gets passed strings that don't begin with whitespace characters.
2015-02-12 23:31:06 +05:30
Syoyo Fujita
a67a60d19f Update README. 2015-02-07 00:04:17 +09:00
Syoyo Fujita
672f252195 Fix per-face material. 2015-02-07 00:01:37 +09:00
Syoyo Fujita
6796d61d07 Merge branch 'master' of github.com:syoyo/tinyobjloader 2015-02-02 17:43:28 +09:00
Syoyo Fujita
0a500b77e7 Small update for README. 2015-02-02 17:43:08 +09:00
Syoyo Fujita
5e5095cb8d Merge pull request #26 from maskman113/master
Fixed cmake warning that targets shouldn't be named test.
2015-01-27 11:25:30 +09:00
Maurice Laveaux
41db59cde5 Fixed cmake warning that targets shouldn't be named test. 2015-01-26 17:32:56 +01:00
Syoyo Fujita
fae5b03e7c Update README. 2015-01-17 23:04:15 +09:00
Syoyo Fujita
276c7e151e Update drone.yml
Add Zup conversion in obj_writer.
2015-01-17 22:37:31 +09:00
Syoyo Fujita
4779593e44 Update drone.yml. 2015-01-17 22:30:02 +09:00
Syoyo Fujita
b5352a642b Add drone.yml 2015-01-17 22:27:20 +09:00
Syoyo Fujita
062f7a1b6d Merge branch 'master' of github.com:syoyo/tinyobjloader 2014-11-30 13:00:05 +09:00
Syoyo Fujita
c5ed61f358 Add link to IBLBaker. 2014-11-30 11:59:55 +09:00
Syoyo Fujita
d535310c94 Merge pull request #24 from Ododo/master
Fix bugs in python module.
2014-11-17 16:28:35 -06:00
Syoyo Fujita
9b69811bb6 Merge branch 'master' of https://github.com/Ododo/tinyobjloader 2014-11-17 16:27:50 -06:00
root
aabdad4bc4 changed to switch structure 2014-11-17 22:06:25 +01:00
root
9587ad9aee cleaning code.. 2014-11-16 23:53:21 +01:00
root
93d7232614 fix shapes / adding setup file 2014-11-16 23:39:20 +01:00
Ododo
e5bbda3835 Update howto.py 2014-11-16 21:08:44 +01:00
root
f750f3faeb adding setup.py file 2014-11-16 19:35:18 +01:00
Syoyo Fujita
c1ed13c36c Merge pull request #23 from Ododo/master
Python interface
2014-11-15 11:54:38 +09:00
root
878a6560cd fix makefile 2014-11-14 15:22:50 +01:00
root
80b243092b base of python module 2014-11-14 14:32:20 +01:00
Julian Simioni
b214cfb4b9 Fix unused variable warnings 2014-10-29 18:54:35 -07:00
Syoyo Fujita
b35f4989ad Add link to mallie. 2014-09-29 19:08:46 +09:00
19 changed files with 1548 additions and 316 deletions

10
.drone.yml Normal file
View File

@@ -0,0 +1,10 @@
image: syoyo/ubu-dev
script:
- curl -L -o premake4 https://github.com/syoyo/orebuildenv/blob/master/build/linux/bin/premake4?raw=true
- chmod +x ./premake4
- ./premake4 gmake
- make
notify:
email:
recipients:
- syoyo@lighttransport.com

View File

@@ -26,18 +26,26 @@ add_library(tinyobjloader
${tinyobjloader-Source} ${tinyobjloader-Source}
) )
add_executable(test ${tinyobjloader-Test-Source}) option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Test Loader Application" OFF)
target_link_libraries(test tinyobjloader)
add_executable(obj_sticher ${tinyobjloader-examples-objsticher}) if(TINYOBJLOADER_BUILD_TEST_LOADER)
target_link_libraries(obj_sticher tinyobjloader) add_executable(test_loader ${tinyobjloader-Test-Source})
target_link_libraries(test_loader tinyobjloader)
endif()
#Installation option(TINYOBJLOADER_BUILD_OBJ_STICHER "Build OBJ Sticher Application" OFF)
install ( TARGETS if (TINYOBJLOADER_BUILD_OBJ_STICHER)
add_executable(obj_sticher ${tinyobjloader-examples-objsticher})
target_link_libraries(obj_sticher tinyobjloader)
install ( TARGETS
obj_sticher obj_sticher
DESTINATION DESTINATION
bin bin
) )
endif()
#Installation
install ( TARGETS install ( TARGETS
tinyobjloader tinyobjloader
DESTINATION DESTINATION

View File

@@ -3,15 +3,21 @@ tinyobjloader
[![wercker status](https://app.wercker.com/status/495a3bac400212cdacdeb4dd9397bf4f/m "wercker status")](https://app.wercker.com/project/bykey/495a3bac400212cdacdeb4dd9397bf4f) [![wercker status](https://app.wercker.com/status/495a3bac400212cdacdeb4dd9397bf4f/m "wercker status")](https://app.wercker.com/project/bykey/495a3bac400212cdacdeb4dd9397bf4f)
[![Build status](https://ci.appveyor.com/api/projects/status/tlb421q3t2oyobcn/branch/master?svg=true)](https://ci.appveyor.com/project/syoyo/tinyobjloader/branch/master)
http://syoyo.github.io/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. 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 ;-) `tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-)
What's new What's new
---------- ----------
* Jun 23, 2015 : Various fixes and added more projects using tinyobjloader. Thanks many contributors!
* Mar 03, 2015 : Replace atof() with hand-written parser for robust reading of numeric value. Thanks skurmedel!
* Feb 06, 2015 : Fix parsing multi-material object
* Sep 14, 2014 : Add support for multi-material per object/group. Thanks Mykhailo! * Sep 14, 2014 : Add support for multi-material per object/group. Thanks Mykhailo!
* Mar 17, 2014 : Fixed trim newline bugs. Thanks ardneran! * Mar 17, 2014 : Fixed trim newline bugs. Thanks ardneran!
* Apr 29, 2014 : Add API to read .obj from std::istream. Good for reading compressed .obj or connecting to procedural primitive generator. Thanks burnse! * Apr 29, 2014 : Add API to read .obj from std::istream. Good for reading compressed .obj or connecting to procedural primitive generator. Thanks burnse!
@@ -37,6 +43,12 @@ TinyObjLoader is successfully used in ...
* bullet3 https://github.com/erwincoumans/bullet3 * bullet3 https://github.com/erwincoumans/bullet3
* pbrt-v2 https://https://github.com/mmp/pbrt-v2 * pbrt-v2 https://https://github.com/mmp/pbrt-v2
* OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01 * OpenGL game engine development http://swarminglogic.com/jotting/2013_10_gamedev01
* mallie https://lighttransport.github.io/mallie
* IBLBaker (Image Based Lighting Baker). http://www.derkreature.com/iblbaker/
* Stanford CS148 http://web.stanford.edu/class/cs148/assignments/assignment3.pdf
* Awesome Bump http://awesomebump.besaba.com/about/
* sdlgl3-wavefront OpenGL .obj viewer https://github.com/chrisliebert/sdlgl3-wavefront
* pbrt-v3 https://https://github.com/mmp/pbrt-v3
* Your project here! * Your project here!
Features Features
@@ -47,7 +59,7 @@ Features
* Texcoord * Texcoord
* Normal * Normal
* Material * Material
* Unknown material attributes are treated as key-value. * Unknown material attributes are returned as key-value(value is string) map.
Notes Notes
----- -----
@@ -57,7 +69,7 @@ Polygon is converted into triangle.
TODO TODO
---- ----
* Support quad polygon and some tags for OpenSubdiv http://graphics.pixar.com/opensubdiv/ - [ ] Support quad polygon and some tags for OpenSubdiv http://graphics.pixar.com/opensubdiv/
License License
------- -------

12
appveyor.yml Normal file
View File

@@ -0,0 +1,12 @@
version: 0.9.{build}
# scripts that runs after repo cloning.
install:
- vcsetup.bat
platform: x64
configuration: Release
build:
parallel: true
project: TinyObjLoaderSolution.sln

View File

@@ -0,0 +1,146 @@
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
# original cornell box data
# comment
# empty line including some space
mtllib cornell_box.mtl
o floor
usemtl white
v 552.8 0.0 0.0
v 0.0 0.0 0.0
v 0.0 0.0 559.2
v 549.6 0.0 559.2
v 130.0 0.0 65.0
v 82.0 0.0 225.0
v 240.0 0.0 272.0
v 290.0 0.0 114.0
v 423.0 0.0 247.0
v 265.0 0.0 296.0
v 314.0 0.0 456.0
v 472.0 0.0 406.0
f 1 2 3 4
f 8 7 6 5
f 12 11 10 9
o light
usemtl light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
usemtl white
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
usemtl white
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
usemtl blue
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
usemtl green
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
usemtl red
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
usemtl white
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
usemtl white
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
usemtl white
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
usemtl green
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

View File

@@ -81,6 +81,7 @@ main(
std::vector<Shape> shapes; std::vector<Shape> shapes;
std::vector<Material> materials; std::vector<Material> materials;
shapes.resize(num_objfiles); shapes.resize(num_objfiles);
materials.resize(num_objfiles);
for (int i = 0; i < num_objfiles; i++) { for (int i = 0; i < num_objfiles; i++) {
std::cout << "Loading " << argv[i+1] << " ... " << std::flush; std::cout << "Loading " << argv[i+1] << " ... " << std::flush;
@@ -98,7 +99,8 @@ main(
std::vector<tinyobj::material_t> out_material; std::vector<tinyobj::material_t> out_material;
StichObjs(out_shape, out_material, shapes, materials); StichObjs(out_shape, out_material, shapes, materials);
bool ret = WriteObj(out_filename, out_shape, out_material); bool coordTransform = true;
bool ret = WriteObj(out_filename, out_shape, out_material, coordTransform);
assert(ret); assert(ret);
return 0; return 0;

View File

@@ -38,7 +38,7 @@ bool WriteMat(const std::string& filename, const std::vector<tinyobj::material_t
return true; return true;
} }
bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials) { bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform) {
FILE* fp = fopen(filename.c_str(), "w"); FILE* fp = fopen(filename.c_str(), "w");
if (!fp) { if (!fp) {
fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str()); fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str());
@@ -74,18 +74,31 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
int idx = shapes[i].mesh.indices[3*k+j]; int idx = shapes[i].mesh.indices[3*k+j];
if (coordTransform) {
fprintf(fp, "v %f %f %f\n",
shapes[i].mesh.positions[3*idx+0],
shapes[i].mesh.positions[3*idx+2],
-shapes[i].mesh.positions[3*idx+1]);
} else {
fprintf(fp, "v %f %f %f\n", fprintf(fp, "v %f %f %f\n",
shapes[i].mesh.positions[3*idx+0], shapes[i].mesh.positions[3*idx+0],
shapes[i].mesh.positions[3*idx+1], shapes[i].mesh.positions[3*idx+1],
shapes[i].mesh.positions[3*idx+2]); shapes[i].mesh.positions[3*idx+2]);
} }
} }
}
// facevarying normal // facevarying normal
if (shapes[i].mesh.normals.size() > 0) { if (shapes[i].mesh.normals.size() > 0) {
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
int idx = shapes[i].mesh.indices[3*k+j]; int idx = shapes[i].mesh.indices[3*k+j];
if (coordTransform) {
fprintf(fp, "vn %f %f %f\n",
shapes[i].mesh.normals[3*idx+0],
shapes[i].mesh.normals[3*idx+2],
-shapes[i].mesh.normals[3*idx+1]);
} else {
fprintf(fp, "vn %f %f %f\n", fprintf(fp, "vn %f %f %f\n",
shapes[i].mesh.normals[3*idx+0], shapes[i].mesh.normals[3*idx+0],
shapes[i].mesh.normals[3*idx+1], shapes[i].mesh.normals[3*idx+1],
@@ -93,6 +106,7 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
} }
} }
} }
}
if (shapes[i].mesh.normals.size() > 0) has_vn = true; if (shapes[i].mesh.normals.size() > 0) has_vn = true;
// facevarying texcoord // facevarying texcoord
@@ -119,6 +133,10 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
int v1 = (3*k + 1) + 1 + v_offset; int v1 = (3*k + 1) + 1 + v_offset;
int v2 = (3*k + 2) + 1 + v_offset; int v2 = (3*k + 2) + 1 + v_offset;
int vt0 = (3*k + 0) + 1 + vt_offset;
int vt1 = (3*k + 1) + 1 + vt_offset;
int vt2 = (3*k + 2) + 1 + vt_offset;
int material_id = shapes[i].mesh.material_ids[k]; int material_id = shapes[i].mesh.material_ids[k];
if (material_id != prev_material_id) { if (material_id != prev_material_id) {
std::string material_name = materials[material_id].name; std::string material_name = materials[material_id].name;
@@ -128,7 +146,7 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
if (has_vn && has_vt) { if (has_vn && has_vt) {
fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
v0, v0, v0, v1, v1, v1, v2, v2, v2); v0, vt0, v0, v1, vt1, v1, v2, vt2, v2);
} else if (has_vn && !has_vt) { } else if (has_vn && !has_vt) {
fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2); fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
} else if (!has_vn && has_vt) { } else if (!has_vn && has_vt) {
@@ -141,7 +159,7 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
v_offset += shapes[i].mesh.indices.size(); v_offset += shapes[i].mesh.indices.size();
//vn_offset += shapes[i].mesh.normals.size() / 3; //vn_offset += shapes[i].mesh.normals.size() / 3;
//vt_offset += shapes[i].mesh.texcoords.size() / 2; vt_offset += shapes[i].mesh.texcoords.size() / 2;
} }

View File

@@ -3,7 +3,7 @@
#include "../../tiny_obj_loader.h" #include "../../tiny_obj_loader.h"
extern bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials); extern bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform = false);
#endif // __OBJ_WRITER_H__ #endif // __OBJ_WRITER_H__

View File

@@ -11,7 +11,7 @@ solution "TinyObjLoaderSolution"
configurations { "Release", "Debug" } configurations { "Release", "Debug" }
if (os.is("windows")) then if (os.is("windows")) then
platforms { "x32", "x64" } platforms { "x64", "x32" }
else else
platforms { "native", "x32", "x64" } platforms { "native", "x32", "x64" }
end end

View File

@@ -0,0 +1,601 @@
{
"shapes": {
"ceiling": {
"texcoords": [],
"positions": [
556.0,
548.7999877929688,
0.0,
556.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
0.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
0.0,
0.0
],
"normals": []
},
"floor": {
"texcoords": [],
"positions": [
552.7999877929688,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
559.2000122070312,
549.5999755859375,
0.0,
559.2000122070312,
290.0,
0.0,
114.0,
240.0,
0.0,
272.0,
82.0,
0.0,
225.0,
130.0,
0.0,
65.0,
472.0,
0.0,
406.0,
314.0,
0.0,
456.0,
265.0,
0.0,
296.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"light": {
"texcoords": [],
"positions": [
343.0,
548.0,
227.0,
343.0,
548.0,
332.0,
213.0,
548.0,
332.0,
213.0,
548.0,
227.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
4.0,
4.0
],
"normals": []
},
"green_wall": {
"texcoords": [],
"positions": [
0.0,
0.0,
559.2000122070312,
0.0,
0.0,
0.0,
0.0,
548.7999877929688,
0.0,
0.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
2.0,
2.0
],
"normals": []
},
"back_wall": {
"texcoords": [],
"positions": [
549.5999755859375,
0.0,
559.2000122070312,
0.0,
0.0,
559.2000122070312,
0.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
0.0,
0.0
],
"normals": []
},
"short_block": {
"texcoords": [],
"positions": [
130.0,
165.0,
65.0,
82.0,
165.0,
225.0,
240.0,
165.0,
272.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
290.0,
165.0,
114.0,
240.0,
165.0,
272.0,
240.0,
0.0,
272.0,
130.0,
0.0,
65.0,
130.0,
165.0,
65.0,
290.0,
165.0,
114.0,
290.0,
0.0,
114.0,
82.0,
0.0,
225.0,
82.0,
165.0,
225.0,
130.0,
165.0,
65.0,
130.0,
0.0,
65.0,
240.0,
0.0,
272.0,
240.0,
165.0,
272.0,
82.0,
165.0,
225.0,
82.0,
0.0,
225.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0,
12.0,
13.0,
14.0,
12.0,
14.0,
15.0,
16.0,
17.0,
18.0,
16.0,
18.0,
19.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"tall_block": {
"texcoords": [],
"positions": [
423.0,
0.0,
247.0,
423.0,
330.0,
247.0,
472.0,
330.0,
406.0,
472.0,
0.0,
406.0,
472.0,
0.0,
406.0,
472.0,
330.0,
406.0,
314.0,
330.0,
456.0,
314.0,
0.0,
456.0,
314.0,
0.0,
456.0,
314.0,
330.0,
456.0,
265.0,
330.0,
296.0,
265.0,
0.0,
296.0,
265.0,
0.0,
296.0,
265.0,
330.0,
296.0,
423.0,
330.0,
247.0,
423.0,
0.0,
247.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0,
4.0,
5.0,
6.0,
4.0,
6.0,
7.0,
8.0,
9.0,
10.0,
8.0,
10.0,
11.0,
12.0,
13.0,
14.0,
12.0,
14.0,
15.0
],
"material_ids": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"normals": []
},
"red_wall": {
"texcoords": [],
"positions": [
552.7999877929688,
0.0,
0.0,
549.5999755859375,
0.0,
559.2000122070312,
556.0,
548.7999877929688,
559.2000122070312,
556.0,
548.7999877929688,
0.0
],
"indicies": [
0.0,
1.0,
2.0,
0.0,
2.0,
3.0
],
"material_ids": [
1.0,
1.0
],
"normals": []
}
},
"materials": {
"blue": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
0.0,
0.0,
1.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"light": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"ambient": [
20.0,
20.0,
20.0
],
"dissolve": 1.0
},
"white": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
1.0,
1.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"green": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
0.0,
1.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
},
"red": {
"transmittance": [
0.0,
0.0,
0.0
],
"illum": 0,
"emission": [
0.0,
0.0,
0.0
],
"diffuse_texname": "",
"ambient_texname": "",
"normal_texname": "",
"shininess": 1.0,
"ior": 1.0,
"specular": [
0.0,
0.0,
0.0
],
"specular_texname": "",
"diffuse": [
1.0,
0.0,
0.0
],
"ambient": [
0.0,
0.0,
0.0
],
"dissolve": 1.0
}
}
}

11
python/howto.py Normal file
View File

@@ -0,0 +1,11 @@
import tinyobjloader as tol
import json
model = tol.LoadObj("cornell_box.obj")
#print(model["shapes"], model["materials"])
print( json.dumps(model, indent=4) )
#see cornell_box_output.json

148
python/main.cpp Normal file
View File

@@ -0,0 +1,148 @@
//python3 module for tinyobjloader
//
//usage:
// import tinyobjloader as tol
// model = tol.LoadObj(name)
// print(model["shapes"])
// print(model["materials"]
#include <Python.h>
#include <vector>
#include "../tiny_obj_loader.h"
typedef std::vector<double> vectd;
PyObject*
pyTupleFromfloat3 (float array[3])
{
int i;
PyObject* tuple = PyTuple_New(3);
for(i=0; i<=2 ; i++){
PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i]));
}
return tuple;
}
extern "C"
{
static PyObject*
pyLoadObj(PyObject* self, PyObject* args)
{
PyObject *rtndict, *pyshapes, *pymaterials,
*current, *meshobj;
char const* filename;
char *current_name;
vectd vect;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
if(!PyArg_ParseTuple(args, "s", &filename))
return NULL;
tinyobj::LoadObj(shapes, materials, filename);
pyshapes = PyDict_New();
pymaterials = PyDict_New();
rtndict = PyDict_New();
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin() ;
shape != shapes.end(); shape++)
{
meshobj = PyDict_New();
tinyobj::mesh_t cm = (*shape).mesh;
for (int i = 0; i <= 4; i++ )
{
current = PyList_New(0);
switch(i) {
case 0:
current_name = "positions";
vect = vectd(cm.positions.begin(), cm.positions.end()); break;
case 1:
current_name = "normals";
vect = vectd(cm.normals.begin(), cm.normals.end()); break;
case 2:
current_name = "texcoords";
vect = vectd(cm.texcoords.begin(), cm.texcoords.end()); break;
case 3:
current_name = "indicies";
vect = vectd(cm.indices.begin(), cm.indices.end()); break;
case 4:
current_name = "material_ids";
vect = vectd(cm.material_ids.begin(), cm.material_ids.end()); break;
}
for (vectd::iterator it = vect.begin() ;
it != vect.end(); it++)
{
PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it));
}
PyDict_SetItemString(meshobj, current_name, current);
}
PyDict_SetItemString(pyshapes, (*shape).name.c_str(), meshobj);
}
for (std::vector<tinyobj::material_t>::iterator mat = materials.begin() ;
mat != materials.end(); mat++)
{
PyObject *matobj = PyDict_New();
PyDict_SetItemString(matobj, "shininess", PyFloat_FromDouble((*mat).shininess));
PyDict_SetItemString(matobj, "ior", PyFloat_FromDouble((*mat).ior));
PyDict_SetItemString(matobj, "dissolve", PyFloat_FromDouble((*mat).dissolve));
PyDict_SetItemString(matobj, "illum", PyLong_FromLong((*mat).illum));
PyDict_SetItemString(matobj, "ambient_texname", PyUnicode_FromString((*mat).ambient_texname.c_str()));
PyDict_SetItemString(matobj, "diffuse_texname", PyUnicode_FromString((*mat).diffuse_texname.c_str()));
PyDict_SetItemString(matobj, "specular_texname", PyUnicode_FromString((*mat).specular_texname.c_str()));
PyDict_SetItemString(matobj, "normal_texname", PyUnicode_FromString((*mat).normal_texname.c_str()));
PyDict_SetItemString(matobj, "ambient", pyTupleFromfloat3((*mat).ambient));
PyDict_SetItemString(matobj, "diffuse", pyTupleFromfloat3((*mat).diffuse));
PyDict_SetItemString(matobj, "specular", pyTupleFromfloat3((*mat).specular));
PyDict_SetItemString(matobj, "transmittance", pyTupleFromfloat3((*mat).transmittance));
PyDict_SetItemString(matobj, "emission", pyTupleFromfloat3((*mat).emission));
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj);
}
PyDict_SetItemString(rtndict, "shapes", pyshapes);
PyDict_SetItemString(rtndict, "materials", pymaterials);
return rtndict;
}
static PyMethodDef mMethods[] = {
{"LoadObj", pyLoadObj, METH_VARARGS},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"tinyobjloader",
NULL,
-1,
mMethods
};
PyMODINIT_FUNC
PyInit_tinyobjloader(void)
{
return PyModule_Create(&moduledef);
}
}

96
python/pyTOL.cbp.mak Normal file
View File

@@ -0,0 +1,96 @@
#------------------------------------------------------------------------------#
# This makefile was generated by 'cbp2make' tool rev.147 #
#------------------------------------------------------------------------------#
WORKDIR = `pwd`
CC = gcc
CXX = g++
AR = ar
LD = g++
WINDRES = windres
INC =
CFLAGS = -Wall -fexceptions `python3-config --cflags`
RESINC =
LIBDIR =
LIB =
LDFLAGS = `python3-config --ldflags`
INC_DEBUG = $(INC)
CFLAGS_DEBUG = $(CFLAGS) -g
RESINC_DEBUG = $(RESINC)
RCFLAGS_DEBUG = $(RCFLAGS)
LIBDIR_DEBUG = $(LIBDIR)
LIB_DEBUG = $(LIB)
LDFLAGS_DEBUG = $(LDFLAGS)
OBJDIR_DEBUG = obj/Debug
DEP_DEBUG =
OUT_DEBUG = bin/Debug/tinyobjloader.so
INC_RELEASE = $(INC)
CFLAGS_RELEASE = $(CFLAGS) -O2
RESINC_RELEASE = $(RESINC)
RCFLAGS_RELEASE = $(RCFLAGS)
LIBDIR_RELEASE = $(LIBDIR)
LIB_RELEASE = $(LIB)
LDFLAGS_RELEASE = $(LDFLAGS) -s
OBJDIR_RELEASE = obj/Release
DEP_RELEASE =
OUT_RELEASE = bin/Release/tinyobjloader.so
OBJ_DEBUG = $(OBJDIR_DEBUG)/main.o $(OBJDIR_DEBUG)/tiny_obj_loader.o
OBJ_RELEASE = $(OBJDIR_RELEASE)/main.o $(OBJDIR_RELEASE)/tiny_obj_loader.o
all: debug release
clean: clean_debug clean_release
before_debug:
test -d bin/Debug || mkdir -p bin/Debug
test -d $(OBJDIR_DEBUG) || mkdir -p $(OBJDIR_DEBUG)
after_debug:
debug: before_debug out_debug after_debug
out_debug: before_debug $(OBJ_DEBUG) $(DEP_DEBUG)
$(LD) -shared $(LIBDIR_DEBUG) $(OBJ_DEBUG) -o $(OUT_DEBUG) $(LDFLAGS_DEBUG) $(LIB_DEBUG)
$(OBJDIR_DEBUG)/main.o: main.cpp
$(CXX) $(CFLAGS_DEBUG) $(INC_DEBUG) -c main.cpp -o $(OBJDIR_DEBUG)/main.o
$(OBJDIR_DEBUG)/tiny_obj_loader.o: ../tiny_obj_loader.cc
$(CC) $(CFLAGS_DEBUG) $(INC_DEBUG) -c ../tiny_obj_loader.cc -o $(OBJDIR_DEBUG)/tiny_obj_loader.o
clean_debug:
rm -f $(OBJ_DEBUG) $(OUT_DEBUG)
rm -rf bin/Debug
rm -rf $(OBJDIR_DEBUG)
before_release:
test -d bin/Release || mkdir -p bin/Release
test -d $(OBJDIR_RELEASE) || mkdir -p $(OBJDIR_RELEASE)
after_release:
release: before_release out_release after_release
out_release: before_release $(OBJ_RELEASE) $(DEP_RELEASE)
$(LD) -shared $(LIBDIR_RELEASE) $(OBJ_RELEASE) -o $(OUT_RELEASE) $(LDFLAGS_RELEASE) $(LIB_RELEASE)
$(OBJDIR_RELEASE)/main.o: main.cpp
$(CXX) $(CFLAGS_RELEASE) $(INC_RELEASE) -c main.cpp -o $(OBJDIR_RELEASE)/main.o
$(OBJDIR_RELEASE)/tiny_obj_loader.o: ../tiny_obj_loader.cc
$(CC) $(CFLAGS_RELEASE) $(INC_RELEASE) -c ../tiny_obj_loader.cc -o $(OBJDIR_RELEASE)/tiny_obj_loader.o
clean_release:
rm -f $(OBJ_RELEASE) $(OUT_RELEASE)
rm -rf bin/Release
rm -rf $(OBJDIR_RELEASE)
.PHONY: before_debug after_debug clean_debug before_release after_release clean_release

13
python/setup.py Normal file
View File

@@ -0,0 +1,13 @@
from distutils.core import setup, Extension
m = Extension('tinyobjloader',
sources = ['main.cpp', '../tiny_obj_loader.cc'])
setup (name = 'tinyobjloader',
version = '0.1',
description = 'Python module for tinyobjloader',
ext_modules = [m])

View File

@@ -15,6 +15,8 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::ve
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str()); printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size()); printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
printf("Size of shape[%ld].normal_indices: %ld\n", i, shapes[i].mesh.normal_indices.size());
printf("Size of shape[%ld].texcoord_indices: %ld\n", i, shapes[i].mesh.texcoord_indices.size());
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size()); printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0); assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) { for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {

507
tiny_obj_loader.cc Executable file → Normal file
View File

@@ -1,26 +1,33 @@
// //
// Copyright 2012-2013, Syoyo Fujita. // Copyright 2012-2015, Syoyo Fujita.
// //
// Licensed under 2-clause BSD liecense. // Licensed under 2-clause BSD liecense.
// //
// //
// version 0.9.7: Support multi-materials(per-face material ID) per object/group. // version 0.9.12: Fix groups being ignored if they have 'usemtl' just before 'g' (#44)
// version 0.9.6: Support Ni(index of refraction) mtl parameter. // version 0.9.11: Invert `Tr` parameter(#43)
// version 0.9.10: Fix seg fault on windows.
// version 0.9.9 : Replace atof() with custom parser.
// version 0.9.8 : Fix multi-materials(per-face material ID).
// version 0.9.7 : Support multi-materials(per-face material ID) per
// object/group.
// version 0.9.6 : Support Ni(index of refraction) mtl parameter.
// Parse transmittance material parameter correctly. // Parse transmittance material parameter correctly.
// version 0.9.5: Parse multiple group name. // version 0.9.5 : Parse multiple group name.
// Add support of specifying the base path to load material file. // Add support of specifying the base path to load material file.
// version 0.9.4: Initial suupport of group tag(g) // version 0.9.4 : Initial suupport of group tag(g)
// version 0.9.3: Fix parsing triple 'x/y/z' // version 0.9.3 : Fix parsing triple 'x/y/z'
// version 0.9.2: Add more .mtl load support // version 0.9.2 : Add more .mtl load support
// version 0.9.1: Add initial .mtl load support // version 0.9.1 : Add initial .mtl load support
// version 0.9.0: Initial // version 0.9.0 : Initial
// //
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <cmath>
#include <cstddef>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -32,19 +39,23 @@
namespace tinyobj { namespace tinyobj {
#define TINYOBJ_SSCANF_BUFFER_SIZE (4096)
struct vertex_index { struct vertex_index {
int v_idx, vt_idx, vn_idx; int v_idx, vt_idx, vn_idx;
vertex_index() {}; vertex_index(){};
vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}; vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx){};
vertex_index(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}; vertex_index(int vidx, int vtidx, int vnidx)
: v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx){};
}; };
// for std::map // for std::map
static inline bool operator<(const vertex_index& a, const vertex_index& b) static inline bool operator<(const vertex_index &a, const vertex_index &b) {
{ if (a.v_idx != b.v_idx)
if (a.v_idx != b.v_idx) return (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.vn_idx != b.vn_idx)
if (a.vt_idx != b.vt_idx) return (a.vt_idx < b.vt_idx); return (a.vn_idx < b.vn_idx);
if (a.vt_idx != b.vt_idx)
return (a.vt_idx < b.vt_idx);
return false; return false;
} }
@@ -55,81 +66,209 @@ struct obj_shape {
std::vector<float> vt; std::vector<float> vt;
}; };
static inline bool isSpace(const char c) { static inline bool isSpace(const char c) { return (c == ' ') || (c == '\t'); }
return (c == ' ') || (c == '\t');
}
static inline bool isNewLine(const char c) { static inline bool isNewLine(const char c) {
return (c == '\r') || (c == '\n') || (c == '\0'); return (c == '\r') || (c == '\n') || (c == '\0');
} }
// Make index zero-base, and also support relative index. // Make index zero-base, and also support relative index.
static inline int fixIndex(int idx, int n) static inline int fixIndex(int idx, int n) {
{ if (idx > 0) return idx - 1;
int i; if (idx == 0) return 0;
return n + idx; // negative value = relative
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) static inline std::string parseString(const char *&token) {
{
std::string s; std::string s;
int b = strspn(token, " \t"); token += strspn(token, " \t");
int e = strcspn(token, " \t\r"); size_t e = strcspn(token, " \t\r");
s = std::string(&token[b], &token[e]); s = std::string(token, &token[e]);
token += e;
token += (e - b);
return s; return s;
} }
static inline int parseInt(const char*& token) static inline int parseInt(const char *&token) {
{
token += strspn(token, " \t"); token += strspn(token, " \t");
int i = atoi(token); int i = atoi(token);
token += strcspn(token, " \t\r"); token += strcspn(token, " \t\r");
return i; return i;
} }
static inline float parseFloat(const char*& token)
// Tries to parse a floating point number located at s.
//
// s_end should be a location in the string where reading should absolutely
// stop. For example at the end of the string, to prevent buffer overflows.
//
// Parses the following EBNF grammar:
// sign = "+" | "-" ;
// END = ? anything not in digit ?
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
// integer = [sign] , digit , {digit} ;
// decimal = integer , ["." , integer] ;
// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
//
// Valid strings are for example:
// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2
//
// If the parsing is a success, result is set to the parsed value and true
// is returned.
//
// The function is greedy and will parse until any of the following happens:
// - a non-conforming character is encountered.
// - s_end is reached.
//
// The following situations triggers a failure:
// - s >= s_end.
// - parse failure.
//
static bool tryParseDouble(const char *s, const char *s_end, double *result)
{ {
if (s >= s_end)
{
return false;
}
double mantissa = 0.0;
// This exponent is base 2 rather than 10.
// However the exponent we parse is supposed to be one of ten,
// thus we must take care to convert the exponent/and or the
// mantissa to a * 2^E, where a is the mantissa and E is the
// exponent.
// To get the final double we will use ldexp, it requires the
// exponent to be in base 2.
int exponent = 0;
// NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED
// TO JUMP OVER DEFINITIONS.
char sign = '+';
char exp_sign = '+';
char const *curr = s;
// How many characters were read in a loop.
int read = 0;
// Tells whether a loop terminated due to reaching s_end.
bool end_not_reached = false;
/*
BEGIN PARSING.
*/
// Find out what sign we've got.
if (*curr == '+' || *curr == '-')
{
sign = *curr;
curr++;
}
else if (isdigit(*curr)) { /* Pass through. */ }
else
{
goto fail;
}
// Read the integer part.
while ((end_not_reached = (curr != s_end)) && isdigit(*curr))
{
mantissa *= 10;
mantissa += static_cast<int>(*curr - 0x30);
curr++; read++;
}
// We must make sure we actually got something.
if (read == 0)
goto fail;
// We allow numbers of form "#", "###" etc.
if (!end_not_reached)
goto assemble;
// Read the decimal part.
if (*curr == '.')
{
curr++;
read = 1;
while ((end_not_reached = (curr != s_end)) && isdigit(*curr))
{
// NOTE: Don't use powf here, it will absolutely murder precision.
mantissa += static_cast<int>(*curr - 0x30) * pow(10.0, -read);
read++; curr++;
}
}
else if (*curr == 'e' || *curr == 'E') {}
else
{
goto assemble;
}
if (!end_not_reached)
goto assemble;
// Read the exponent part.
if (*curr == 'e' || *curr == 'E')
{
curr++;
// Figure out if a sign is present and if it is.
if ((end_not_reached = (curr != s_end)) && (*curr == '+' || *curr == '-'))
{
exp_sign = *curr;
curr++;
}
else if (isdigit(*curr)) { /* Pass through. */ }
else
{
// Empty E is not allowed.
goto fail;
}
read = 0;
while ((end_not_reached = (curr != s_end)) && isdigit(*curr))
{
exponent *= 10;
exponent += static_cast<int>(*curr - 0x30);
curr++; read++;
}
exponent *= (exp_sign == '+'? 1 : -1);
if (read == 0)
goto fail;
}
assemble:
*result = (sign == '+'? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent);
return true;
fail:
return false;
}
static inline float parseFloat(const char *&token) {
token += strspn(token, " \t"); token += strspn(token, " \t");
#ifdef TINY_OBJ_LOADER_OLD_FLOAT_PARSER
float f = (float)atof(token); float f = (float)atof(token);
token += strcspn(token, " \t\r"); token += strcspn(token, " \t\r");
#else
const char *end = token + strcspn(token, " \t\r");
double val = 0.0;
tryParseDouble(token, end, &val);
float f = static_cast<float>(val);
token = end;
#endif
return f; return f;
} }
static inline void parseFloat2(
float& x, float& y, static inline void parseFloat2(float &x, float &y, const char *&token) {
const char*& token)
{
x = parseFloat(token); x = parseFloat(token);
y = parseFloat(token); y = parseFloat(token);
} }
static inline void parseFloat3( static inline void parseFloat3(float &x, float &y, float &z,
float& x, float& y, float& z, const char *&token) {
const char*& token)
{
x = parseFloat(token); x = parseFloat(token);
y = parseFloat(token); y = parseFloat(token);
z = parseFloat(token); z = parseFloat(token);
} }
// Parse triples: i, i/j/k, i//k, i/j // Parse triples: i, i/j/k, i//k, i/j
static vertex_index parseTriple( static vertex_index parseTriple(const char *&token, int vsize, int vnsize,
const char* &token, int vtsize) {
int vsize,
int vnsize,
int vtsize)
{
vertex_index vi(-1); vertex_index vi(-1);
vi.v_idx = fixIndex(atoi(token), vsize); vi.v_idx = fixIndex(atoi(token), vsize);
@@ -161,54 +300,54 @@ static vertex_index parseTriple(
return vi; return vi;
} }
static unsigned int static vertex_index
updateVertex( updateVertex(std::map<vertex_index, vertex_index> &vertexCache,
std::map<vertex_index, unsigned int>& vertexCache, std::vector<float> &positions, std::vector<float> &normals,
std::vector<float>& positions, std::vector<float> &texcoords,
std::vector<float>& normals, const std::vector<float> &in_positions,
std::vector<float>& texcoords, const std::vector<float> &in_normals,
const std::vector<float>& in_positions, const std::vector<float> &in_texcoords, const vertex_index &i) {
const std::vector<float>& in_normals, const std::map<vertex_index, vertex_index>::iterator it = vertexCache.find(i);
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()) { if (it != vertexCache.end()) {
// found cache // found cache
return it->second; return it->second;
} }
assert(in_positions.size() > (unsigned int) (3*i.v_idx+2)); assert(in_positions.size() > (unsigned int)(3 * i.v_idx + 2));
positions.push_back(in_positions[3*i.v_idx+0]); 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 + 1]);
positions.push_back(in_positions[3*i.v_idx+2]); positions.push_back(in_positions[3 * i.v_idx + 2]);
if (i.vn_idx >= 0) { if (i.vn_idx >= 0) {
normals.push_back(in_normals[3*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 + 1]);
normals.push_back(in_normals[3*i.vn_idx+2]); normals.push_back(in_normals[3 * i.vn_idx + 2]);
} }
if (i.vt_idx >= 0) { if (i.vt_idx >= 0) {
texcoords.push_back(in_texcoords[2*i.vt_idx+0]); texcoords.push_back(in_texcoords[2 * i.vt_idx + 0]);
texcoords.push_back(in_texcoords[2*i.vt_idx+1]); texcoords.push_back(in_texcoords[2 * i.vt_idx + 1]);
} }
unsigned int idx = positions.size() / 3 - 1; unsigned int v_idx = static_cast<unsigned int>(positions.size() / 3 - 1);
vertexCache[i] = idx; unsigned int vn_idx = static_cast<unsigned int>(normals.size() / 3 - 1);
unsigned int vt_idx = static_cast<unsigned int>(texcoords.size() / 2 - 1);
vertexCache[i].v_idx = v_idx;
vertexCache[i].vn_idx = vn_idx;
vertexCache[i].vt_idx = vt_idx;
return idx; return vertexCache[i];
} }
void InitMaterial(material_t& material) { void InitMaterial(material_t &material) {
material.name = ""; material.name = "";
material.ambient_texname = ""; material.ambient_texname = "";
material.diffuse_texname = ""; material.diffuse_texname = "";
material.specular_texname = ""; material.specular_texname = "";
material.normal_texname = ""; material.normal_texname = "";
for (int i = 0; i < 3; i ++) { for (int i = 0; i < 3; i++) {
material.ambient[i] = 0.f; material.ambient[i] = 0.f;
material.diffuse[i] = 0.f; material.diffuse[i] = 0.f;
material.specular[i] = 0.f; material.specular[i] = 0.f;
@@ -222,29 +361,20 @@ void InitMaterial(material_t& material) {
material.unknown_parameter.clear(); material.unknown_parameter.clear();
} }
static bool static bool exportFaceGroupToShape(
exportFaceGroupToShape( shape_t &shape, std::map<vertex_index, vertex_index> vertexCache,
shape_t& shape,
std::map<vertex_index, unsigned int> vertexCache,
const std::vector<float> &in_positions, const std::vector<float> &in_positions,
const std::vector<float> &in_normals, const std::vector<float> &in_normals,
const std::vector<float> &in_texcoords, const std::vector<float> &in_texcoords,
const std::vector<std::vector<vertex_index> >& faceGroup, const std::vector<std::vector<vertex_index> > &faceGroup,
const int material_id, const int material_id, const std::string &name, bool clearCache) {
const std::string &name,
bool clearCache)
{
if (faceGroup.empty()) { if (faceGroup.empty()) {
return false; return false;
} }
size_t offset;
offset = shape.mesh.indices.size();
// Flatten vertices and indices // Flatten vertices and indices
for (size_t i = 0; i < faceGroup.size(); i++) { for (size_t i = 0; i < faceGroup.size(); i++) {
const std::vector<vertex_index>& face = faceGroup[i]; const std::vector<vertex_index> &face = faceGroup[i];
vertex_index i0 = face[0]; vertex_index i0 = face[0];
vertex_index i1(-1); vertex_index i1(-1);
@@ -257,17 +387,30 @@ exportFaceGroupToShape(
i1 = i2; i1 = i2;
i2 = face[k]; i2 = face[k];
unsigned int v0 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0); vertex_index vi0 = updateVertex(
unsigned int v1 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1); vertexCache, shape.mesh.positions, shape.mesh.normals,
unsigned int v2 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2); shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0);
vertex_index vi1 = updateVertex(
vertexCache, shape.mesh.positions, shape.mesh.normals,
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1);
vertex_index vi2 = updateVertex(
vertexCache, shape.mesh.positions, shape.mesh.normals,
shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2);
shape.mesh.indices.push_back(v0); shape.mesh.indices.push_back(vi0.v_idx);
shape.mesh.indices.push_back(v1); shape.mesh.indices.push_back(vi1.v_idx);
shape.mesh.indices.push_back(v2); shape.mesh.indices.push_back(vi2.v_idx);
shape.mesh.normal_indices.push_back(vi0.vn_idx);
shape.mesh.normal_indices.push_back(vi1.vn_idx);
shape.mesh.normal_indices.push_back(vi2.vn_idx);
shape.mesh.texcoord_indices.push_back(vi0.vt_idx);
shape.mesh.texcoord_indices.push_back(vi1.vt_idx);
shape.mesh.texcoord_indices.push_back(vi2.vt_idx);
shape.mesh.material_ids.push_back(material_id); shape.mesh.material_ids.push_back(material_id);
} }
} }
shape.name = name; shape.name = name;
@@ -276,15 +419,11 @@ exportFaceGroupToShape(
vertexCache.clear(); vertexCache.clear();
return true; return true;
} }
std::string LoadMtl ( std::string LoadMtl(std::map<std::string, int> &material_map,
std::map<std::string, int>& material_map, std::vector<material_t> &materials,
std::vector<material_t>& materials, std::istream &inStream) {
std::istream& inStream)
{
material_map.clear();
std::stringstream err; std::stringstream err;
material_t material; material_t material;
@@ -298,10 +437,12 @@ std::string LoadMtl (
// Trim newline '\r\n' or '\n' // Trim newline '\r\n' or '\n'
if (linebuf.size() > 0) { if (linebuf.size() > 0) {
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); if (linebuf[linebuf.size() - 1] == '\n')
linebuf.erase(linebuf.size() - 1);
} }
if (linebuf.size() > 0) { if (linebuf.size() > 0) {
if (linebuf[linebuf.size()-1] == '\r') linebuf.erase(linebuf.size()-1); if (linebuf[linebuf.size() - 1] == '\r')
linebuf.erase(linebuf.size() - 1);
} }
// Skip if empty line. // Skip if empty line.
@@ -310,20 +451,22 @@ std::string LoadMtl (
} }
// Skip leading space. // Skip leading space.
const char* token = linebuf.c_str(); const char *token = linebuf.c_str();
token += strspn(token, " \t"); token += strspn(token, " \t");
assert(token); assert(token);
if (token[0] == '\0') continue; // empty line if (token[0] == '\0')
continue; // empty line
if (token[0] == '#') continue; // comment line if (token[0] == '#')
continue; // comment line
// new mtl // new mtl
if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) { if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) {
// flush previous material. // flush previous material.
if (!material.name.empty()) if (!material.name.empty()) {
{ material_map.insert(
material_map.insert(std::pair<std::string, int>(material.name, materials.size())); std::pair<std::string, int>(material.name, static_cast<int>(materials.size())));
materials.push_back(material); materials.push_back(material);
} }
@@ -331,9 +474,13 @@ std::string LoadMtl (
InitMaterial(material); InitMaterial(material);
// set new mtl name // set new mtl name
char namebuf[4096]; char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7; token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif
material.name = namebuf; material.name = namebuf;
continue; continue;
} }
@@ -390,7 +537,7 @@ std::string LoadMtl (
} }
// emission // emission
if(token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) { if (token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) {
token += 2; token += 2;
float r, g, b; float r, g, b;
parseFloat3(r, g, b, token); parseFloat3(r, g, b, token);
@@ -401,7 +548,7 @@ std::string LoadMtl (
} }
// shininess // shininess
if(token[0] == 'N' && token[1] == 's' && isSpace(token[2])) { if (token[0] == 'N' && token[1] == 's' && isSpace(token[2])) {
token += 2; token += 2;
material.shininess = parseFloat(token); material.shininess = parseFloat(token);
continue; continue;
@@ -422,7 +569,8 @@ std::string LoadMtl (
} }
if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) { if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) {
token += 2; token += 2;
material.dissolve = parseFloat(token); // Invert value of Tr(assume Tr is in range [0, 1])
material.dissolve = 1.0 - parseFloat(token);
continue; continue;
} }
@@ -455,29 +603,29 @@ std::string LoadMtl (
} }
// unknown parameter // unknown parameter
const char* _space = strchr(token, ' '); const char *_space = strchr(token, ' ');
if(!_space) { if (!_space) {
_space = strchr(token, '\t'); _space = strchr(token, '\t');
} }
if(_space) { if (_space) {
int len = _space - token; std::ptrdiff_t len = _space - token;
std::string key(token, len); std::string key(token, len);
std::string value = _space + 1; std::string value = _space + 1;
material.unknown_parameter.insert(std::pair<std::string, std::string>(key, value)); material.unknown_parameter.insert(
std::pair<std::string, std::string>(key, value));
} }
} }
// flush last material. // flush last material.
material_map.insert(std::pair<std::string, int>(material.name, materials.size())); material_map.insert(
std::pair<std::string, int>(material.name, static_cast<int>(materials.size())));
materials.push_back(material); materials.push_back(material);
return err.str(); return err.str();
} }
std::string MaterialFileReader::operator() ( std::string MaterialFileReader::operator()(const std::string &matId,
const std::string& matId, std::vector<material_t> &materials,
std::vector<material_t>& materials, std::map<std::string, int> &matMap) {
std::map<std::string, int>& matMap)
{
std::string filepath; std::string filepath;
if (!m_mtlBasePath.empty()) { if (!m_mtlBasePath.empty()) {
@@ -490,13 +638,9 @@ std::string MaterialFileReader::operator() (
return LoadMtl(matMap, materials, matIStream); return LoadMtl(matMap, materials, matIStream);
} }
std::string std::string LoadObj(std::vector<shape_t> &shapes,
LoadObj( std::vector<material_t> &materials, // [output]
std::vector<shape_t>& shapes, const char *filename, const char *mtl_basepath) {
std::vector<material_t>& materials, // [output]
const char* filename,
const char* mtl_basepath)
{
shapes.clear(); shapes.clear();
@@ -512,17 +656,14 @@ LoadObj(
if (mtl_basepath) { if (mtl_basepath) {
basePath = mtl_basepath; basePath = mtl_basepath;
} }
MaterialFileReader matFileReader( basePath ); MaterialFileReader matFileReader(basePath);
return LoadObj(shapes, materials, ifs, matFileReader); return LoadObj(shapes, materials, ifs, matFileReader);
} }
std::string LoadObj( std::string LoadObj(std::vector<shape_t> &shapes,
std::vector<shape_t>& shapes, std::vector<material_t> &materials, // [output]
std::vector<material_t>& materials, // [output] std::istream &inStream, MaterialReader &readMatFn) {
std::istream& inStream,
MaterialReader& readMatFn)
{
std::stringstream err; std::stringstream err;
std::vector<float> v; std::vector<float> v;
@@ -533,7 +674,7 @@ std::string LoadObj(
// material // material
std::map<std::string, int> material_map; std::map<std::string, int> material_map;
std::map<vertex_index, unsigned int> vertexCache; std::map<vertex_index, vertex_index> vertexCache;
int material = -1; int material = -1;
shape_t shape; shape_t shape;
@@ -547,10 +688,12 @@ std::string LoadObj(
// Trim newline '\r\n' or '\n' // Trim newline '\r\n' or '\n'
if (linebuf.size() > 0) { if (linebuf.size() > 0) {
if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); if (linebuf[linebuf.size() - 1] == '\n')
linebuf.erase(linebuf.size() - 1);
} }
if (linebuf.size() > 0) { if (linebuf.size() > 0) {
if (linebuf[linebuf.size()-1] == '\r') linebuf.erase(linebuf.size()-1); if (linebuf[linebuf.size() - 1] == '\r')
linebuf.erase(linebuf.size() - 1);
} }
// Skip if empty line. // Skip if empty line.
@@ -559,13 +702,15 @@ std::string LoadObj(
} }
// Skip leading space. // Skip leading space.
const char* token = linebuf.c_str(); const char *token = linebuf.c_str();
token += strspn(token, " \t"); token += strspn(token, " \t");
assert(token); assert(token);
if (token[0] == '\0') continue; // empty line if (token[0] == '\0')
continue; // empty line
if (token[0] == '#') continue; // comment line if (token[0] == '#')
continue; // comment line
// vertex // vertex
if (token[0] == 'v' && isSpace((token[1]))) { if (token[0] == 'v' && isSpace((token[1]))) {
@@ -606,9 +751,10 @@ std::string LoadObj(
std::vector<vertex_index> face; std::vector<vertex_index> face;
while (!isNewLine(token[0])) { while (!isNewLine(token[0])) {
vertex_index vi = parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2); vertex_index vi =
parseTriple(token, static_cast<int>(v.size() / 3), static_cast<int>(vn.size() / 3), static_cast<int>(vt.size() / 2));
face.push_back(vi); face.push_back(vi);
int n = strspn(token, " \t\r"); size_t n = strspn(token, " \t\r");
token += n; token += n;
} }
@@ -620,11 +766,21 @@ std::string LoadObj(
// use mtl // use mtl
if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) { if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) {
char namebuf[4096]; char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7; token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, false); // Create face group per material.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) {
shapes.push_back(shape);
}
shape = shape_t();
faceGroup.clear(); faceGroup.clear();
if (material_map.find(namebuf) != material_map.end()) { if (material_map.find(namebuf) != material_map.end()) {
@@ -635,14 +791,17 @@ std::string LoadObj(
} }
continue; continue;
} }
// load mtl // load mtl
if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) { if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) {
char namebuf[4096]; char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 7; token += 7;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif
std::string err_mtl = readMatFn(namebuf, materials, material_map); std::string err_mtl = readMatFn(namebuf, materials, material_map);
if (!err_mtl.empty()) { if (!err_mtl.empty()) {
@@ -657,14 +816,15 @@ std::string LoadObj(
if (token[0] == 'g' && isSpace((token[1]))) { if (token[0] == 'g' && isSpace((token[1]))) {
// flush previous face group. // flush previous face group.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }
shape = shape_t(); shape = shape_t();
//material = -1; // material = -1;
faceGroup.clear(); faceGroup.clear();
std::vector<std::string> names; std::vector<std::string> names;
@@ -676,7 +836,7 @@ std::string LoadObj(
assert(names.size() > 0); assert(names.size() > 0);
// names[0] must be 'g', so skipt 0th element. // names[0] must be 'g', so skip the 0th element.
if (names.size() > 1) { if (names.size() > 1) {
name = names[1]; name = names[1];
} else { } else {
@@ -690,29 +850,34 @@ std::string LoadObj(
if (token[0] == 'o' && isSpace((token[1]))) { if (token[0] == 'o' && isSpace((token[1]))) {
// flush previous face group. // flush previous face group.
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
faceGroup, material, name, true);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }
//material = -1; // material = -1;
faceGroup.clear(); faceGroup.clear();
shape = shape_t(); shape = shape_t();
// @todo { multiple object name? } // @todo { multiple object name? }
char namebuf[4096]; char namebuf[TINYOBJ_SSCANF_BUFFER_SIZE];
token += 2; token += 2;
#ifdef _MSC_VER
sscanf_s(token, "%s", namebuf, _countof(namebuf));
#else
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif
name = std::string(namebuf); name = std::string(namebuf);
continue; continue;
} }
// Ignore unknown command. // Ignore unknown command.
} }
bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup,
material, name, true);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }
@@ -720,6 +885,4 @@ std::string LoadObj(
return err.str(); return err.str();
} }
} }

View File

@@ -1,5 +1,5 @@
// //
// Copyright 2012-2013, Syoyo Fujita. // Copyright 2012-2015, Syoyo Fujita.
// //
// Licensed under 2-clause BSD liecense. // Licensed under 2-clause BSD liecense.
// //
@@ -12,8 +12,7 @@
namespace tinyobj { namespace tinyobj {
typedef struct typedef struct {
{
std::string name; std::string name;
float ambient[3]; float ambient[3];
@@ -34,45 +33,41 @@ typedef struct
std::map<std::string, std::string> unknown_parameter; std::map<std::string, std::string> unknown_parameter;
} material_t; } material_t;
typedef struct typedef struct {
{
std::vector<float> positions; std::vector<float> positions;
std::vector<float> normals; std::vector<float> normals;
std::vector<float> texcoords; std::vector<float> texcoords;
std::vector<unsigned int> indices; std::vector<unsigned int> indices; // indices for vertex
std::vector<unsigned int> normal_indices; // indices for normal
std::vector<unsigned int> texcoord_indices; // indices for texcoord
std::vector<int> material_ids; // per-mesh material ID std::vector<int> material_ids; // per-mesh material ID
} mesh_t; } mesh_t;
typedef struct typedef struct {
{
std::string name; std::string name;
mesh_t mesh; mesh_t mesh;
} shape_t; } shape_t;
class MaterialReader class MaterialReader {
{
public: public:
MaterialReader(){} MaterialReader() {}
virtual ~MaterialReader(){} virtual ~MaterialReader() {}
virtual std::string operator() ( virtual std::string operator()(const std::string &matId,
const std::string& matId, std::vector<material_t> &materials,
std::vector<material_t>& materials, std::map<std::string, int> &matMap) = 0;
std::map<std::string, int>& matMap) = 0;
}; };
class MaterialFileReader: class MaterialFileReader : public MaterialReader {
public MaterialReader public:
{ MaterialFileReader(const std::string &mtl_basepath)
public: : m_mtlBasePath(mtl_basepath) {}
MaterialFileReader(const std::string& mtl_basepath): m_mtlBasePath(mtl_basepath) {}
virtual ~MaterialFileReader() {} virtual ~MaterialFileReader() {}
virtual std::string operator() ( virtual std::string operator()(const std::string &matId,
const std::string& matId, std::vector<material_t> &materials,
std::vector<material_t>& materials, std::map<std::string, int> &matMap);
std::map<std::string, int>& matMap);
private: private:
std::string m_mtlBasePath; std::string m_mtlBasePath;
}; };
@@ -81,27 +76,21 @@ class MaterialFileReader:
/// The function returns error string. /// The function returns error string.
/// Returns empty string when loading .obj success. /// Returns empty string when loading .obj success.
/// 'mtl_basepath' is optional, and used for base path for .mtl file. /// 'mtl_basepath' is optional, and used for base path for .mtl file.
std::string LoadObj( std::string LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<shape_t>& shapes, // [output] std::vector<material_t> &materials, // [output]
std::vector<material_t>& materials, // [output] const char *filename, const char *mtl_basepath = NULL);
const char* filename,
const char* mtl_basepath = NULL);
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
/// std::istream for materials. /// std::istream for materials.
/// Returns empty string when loading .obj success. /// Returns empty string when loading .obj success.
std::string LoadObj( std::string LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<shape_t>& shapes, // [output] std::vector<material_t> &materials, // [output]
std::vector<material_t>& materials, // [output] std::istream &inStream, MaterialReader &readMatFn);
std::istream& inStream,
MaterialReader& readMatFn);
/// Loads materials into std::map /// Loads materials into std::map
/// Returns an empty string if successful /// Returns an empty string if successful
std::string LoadMtl ( std::string LoadMtl(std::map<std::string, int> &material_map,
std::map<std::string, int>& material_map, std::vector<material_t> &materials, std::istream &inStream);
std::vector<material_t>& materials,
std::istream& inStream);
} }
#endif // _TINY_OBJ_LOADER_H #endif // _TINY_OBJ_LOADER_H

BIN
tools/windows/premake5.exe Normal file

Binary file not shown.

1
vcsetup.bat Normal file
View File

@@ -0,0 +1 @@
.\\tools\\windows\\premake5.exe vs2013