326 Commits

Author SHA1 Message Date
Syoyo Fujita
934788785e Show line number for some warning and error message. 2018-10-10 13:33:11 +09:00
Syoyo Fujita
e07a835f02 Separate error message into warning and error. Breaks API, so bump to version 1.3.0 2018-10-10 01:56:07 +09:00
Syoyo Fujita
1cdfd786d8 Add colorspace extension to texture options. Fixes #184 2018-09-14 13:42:27 +09:00
Syoyo Fujita
803b65b8a0 Merge pull request #183 from mlimper/master
Added option to disable default vertex colors
2018-09-01 00:31:29 +09:00
Max Limper
50518a515b added option to disable default vertex colors 2018-08-31 16:59:32 +02:00
Syoyo Fujita
c9b1bccf97 Fix mis-counting of faces when triangulation is enabled. 2018-08-20 15:10:37 +09:00
Syoyo Fujita
1f17833657 Add comments. 2018-08-20 14:24:49 +09:00
Syoyo Fujita
bb58a8f8c3 Revert assertion equation. 2018-08-20 14:19:34 +09:00
Syoyo Fujita
b1f594d682 Merge branch 'master' of github.com:syoyo/tinyobjloader 2018-08-20 14:10:17 +09:00
Syoyo Fujita
02df4943f9 Fix assert equation. 2018-08-20 14:09:56 +09:00
Syoyo Fujita
826a892d0b Merge pull request #181 from vincentdm05/missing-data
Produce an error and return when indices and data dont match.
2018-08-17 16:12:36 +09:00
Vincent de Marignac
68350e2fc7 give respective warnings but allow partially correct data to be returned 2018-08-16 23:34:47 +03:00
Vincent de Marignac
7d20e9b901 use ternary op instead of max from omitted lib 2018-08-16 00:00:22 +03:00
Vincent de Marignac
fdc70abdc6 fix index comparison wrt array size 2018-08-15 23:41:35 +03:00
Vincent de Marignac
8a885e14b8 Produce an error and return when indices and data dont match. 2018-08-15 23:13:00 +03:00
Syoyo Fujita
cd65de860b Merge branch 'master' of github.com:syoyo/tinyobjloader 2018-08-13 17:47:38 +09:00
Syoyo Fujita
4924857fd3 Add note on # of max threads. 2018-08-13 17:47:13 +09:00
Syoyo Fujita
1a7bdc6192 Parse multiple group names. Fixes #146 2018-08-11 15:21:17 +09:00
Syoyo Fujita
fd06fa49e4 Add unit test for parsing 'l'. 2018-07-25 21:42:23 +09:00
Syoyo Fujita
0d68262246 Fix buffer overrun when parsing 'l' line. 2018-07-25 16:24:40 +09:00
Syoyo Fujita
0e950513a3 Merge pull request #178 from ZKing1000/master
Added support for line paths.
2018-07-25 16:02:49 +09:00
Holden Green
a4b115a584 Hopefully fixed compiling error 2018-07-24 23:47:59 -07:00
Syoyo Fujita
bb3e27d4f3 Merge pull request #179 from mlimper/master
Fixed #177
2018-07-09 19:29:07 +09:00
Max Limper
c4e7e65acb fixed #177 (explicit empty mtl base dir given) 2018-07-09 12:21:46 +02:00
Max Limper
eba327b9c0 make tester fail for issue 177 failing (explicit MTL base dir given by API user) 2018-07-09 12:19:33 +02:00
Holden Green
3cbf45a572 Non const 2018-07-04 22:13:39 -07:00
Holden Green
6650dbf397 Used swap in favor of move 2018-07-04 22:10:45 -07:00
Holden Green
7befd59de4 Removed comment 2018-07-04 21:59:56 -07:00
Holden Green
c5b3139653 Fixed comments 2018-07-04 21:46:42 -07:00
Holden Green
adb2309110 Removed print message. 2018-07-04 21:44:09 -07:00
Holden Green
3edca81a75 Added line paths. 2018-07-04 21:21:56 -07:00
Syoyo Fujita
7a88cddefc Add unit test for issue 177. 2018-07-03 18:37:41 +02:00
Syoyo Fujita
d541711a79 Merge pull request #176 from silverweed/master
Ensure mtl_basedir ends with a directory separator
2018-06-02 00:18:54 +09:00
Syoyo Fujita
d1ce2082f6 Remove afl files since it fails to create file on Windows file system. 2018-06-02 00:15:18 +09:00
silverweed
8fd9f6e57b ensure mtl_basedir ends with a directory separator 2018-06-01 12:02:38 +02:00
Syoyo Fujita
24bd8b49ff Merge branch 'master' of github.com:syoyo/tinyobjloader 2018-05-31 16:34:01 +09:00
Syoyo Fujita
4a0e79985d Bump version. 2018-05-31 16:29:14 +09:00
Syoyo Fujita
06f6139d1f Limit # of tags when parsing SubD tag('t'). 2018-05-31 16:25:39 +09:00
Syoyo Fujita
0c8db8ee23 Hardened implementation(fix some seg faults, out-of-bound access) found by fuzzer. 2018-05-31 15:49:56 +09:00
Syoyo Fujita
64d1e3f883 Merge pull request #170 from Neptilo/master
Fix bug that discarded some chunks.
2018-03-27 00:57:19 +09:00
Victor Ripplinger
a39a6b481c Fix bug that discarded some chunks.
The OBJ loader was discarding the first line of a file
or a chunk following one that ends with a newline.
2018-03-26 16:28:13 +02:00
Syoyo Fujita
bce1bb8387 Merge branch 'master' of github.com:syoyo/tinyobjloader 2018-03-26 20:10:55 +09:00
Syoyo Fujita
7fcfafb39a Fix compilation for double precision mode(Fixes #167). 2018-03-26 20:09:56 +09:00
Syoyo Fujita
5eda671225 Merge pull request #169 from LZaw/master
Adapt 1.0.x format
2018-03-10 00:03:35 +09:00
LZaw
f95510b04b Removed multiplication for color_idx_offset 2018-03-09 13:57:18 +01:00
LZaw
94f1dc15b3 Update obj_sticher.cc 2018-03-09 13:48:05 +01:00
LZaw
a4eabf54b1 Adapt 1.0.x datastructure 2018-03-09 13:43:52 +01:00
Syoyo Fujita
72c38f64d5 Merge pull request #168 from LZaw/master
Adapt the v1.0.x data format to the WriteObj function
2018-03-09 00:57:27 +09:00
LZaw
d174e625a2 Update obj_writer.h 2018-03-08 15:58:39 +01:00
LZaw
707014f843 Update obj_writer.cc 2018-03-08 15:48:45 +01:00
LZaw
12837cc8b2 Adapt v 1.0.x
Added an attributes parameter
2018-03-08 15:47:06 +01:00
Syoyo Fujita
b85714b4cf Skip parsing incomplete or invalid face definition(e.g. f definition only contains 1 or 2 indices). 2018-02-23 20:25:13 +09:00
Syoyo Fujita
e060b4f4aa Remove unused variable. 2018-02-21 20:53:30 +09:00
Syoyo Fujita
2dca72724f Merge pull request #165 from Neptilo/master
Fix bug in not assigning material id to faces
2018-02-21 20:01:23 +09:00
Victor Ripplinger
72529f02fe Material ids were not assigned to faces if the
first face with this material was in another thread buffer than where
the usemtl command was
2018-02-21 11:36:36 +01:00
Syoyo Fujita
16f3041c76 Merge pull request #163 from Neptilo/master
Fix bug when line starts before a chunk and ends after it
2018-02-09 20:10:16 +09:00
Neptilo
73e9b4dc3a Fix bug when line starts before a chunk and ends after it
When a line started in a chunk, the algorithm only looked for its end in the following chunk, but the end of the line may actually be located even further. Instead, in this commit we look for the next new line until the end of the whole buffer.
2018-02-09 11:46:43 +01:00
Syoyo Fujita
5113cd65cf print smoothing group id. 2018-02-04 15:19:42 +09:00
Syoyo Fujita
65df7c4794 Add smooting group test .obj with two squares. 2018-02-04 14:16:14 +09:00
Syoyo Fujita
eaf8623e61 Fix build of viewer example.
Bump version.
2018-02-04 14:05:36 +09:00
Syoyo Fujita
dcad3e6c50 Add per-face smoothing groupd ids to mesh_t.
Add unit test for smoothing groups.
2018-01-31 22:13:52 +09:00
Syoyo Fujita
2dfc37a475 Introduce face_t structure which stores per-face smoothing group and vertex indices. 2018-01-31 20:07:34 +09:00
Syoyo Fujita
9a6390cdee Add padding. 2018-01-31 14:24:37 +09:00
gopalss
78c7c9011a Fix for #29 Normal Generation by Smoothing Group Id - Commit 4 2018-01-30 10:55:10 -05:00
gopalss
1754669b07 Fix for #29 Normal Generation by Smoothing Group Id - Commit 3 2018-01-30 10:31:02 -05:00
gopalss
1f7b4a49c0 Fix for #29 Normal Generation by Smoothing Group Id - Commit 2 2018-01-30 09:51:16 -05:00
gopalss
15f47e2e35 Fix for #29 Normal Generation by Smoothing Group Id 2018-01-29 18:37:39 -05:00
Syoyo Fujita
12bf4165be Fix assertion when there is no normal/texcoord assigned to the face. Fixes #161.
Suppress clang warnings.
2018-01-29 13:41:33 +09:00
Syoyo Fujita
f206a56362 Merge pull request #160 from arosh/master
PR for open bounty test 2.
2018-01-17 01:56:07 +09:00
Sho Iizuka
13951d6459 Remove empty lines at EOF 2018-01-16 18:11:05 +09:00
Syoyo Fujita
5383e3400a Merge pull request #156 from raspofabs/master
ear clipping using pnpoly algorithm
2018-01-15 17:26:11 +09:00
Richard Fabian
ac3c36ffda increase the size of the epsilon to give better axis choice for triangulation 2018-01-14 18:53:20 +00:00
Richard Fabian
3b681805aa fixed the bug where the wrong axis was selected for doing the pnpoly check 2018-01-14 16:45:59 +00:00
Richard Fabian
ca49183639 added ear clipping triangulation 2018-01-14 14:21:46 +00:00
Syoyo Fujita
b29d34f2e1 Merge pull request #154 from ogrex/master
Bugfix for multiple texture
2017-12-21 01:23:03 +09:00
ogrex
cb085d1fb6 fix multiple texture wrong id problem 2017-12-20 22:17:19 +09:00
ogrex
b38e97b7ec trimming '\r' in material_file name 2017-12-20 22:13:58 +09:00
Syoyo Fujita
b434c2497f Update master URL. 2017-10-16 17:48:45 +09:00
Syoyo Fujita
94fc413466 Fix parsing of crease tags(t)
Support parsing texture filename containing whitespace.
2017-10-13 18:13:36 +09:00
Syoyo Fujita
1c6dbf9bd8 Merge branch 'master' of github.com:syoyo/tinyobjloader 2017-10-13 02:04:11 +09:00
Syoyo Fujita
88ad575f62 Initial support of parsing vertex color(extension format) 2017-10-12 19:04:38 +09:00
Syoyo Fujita
5cd30b70e0 Merge pull request #142 from Ododo/master
[Python] Fix mapping for #131 and compilation error #139 #132 (related)
2017-10-08 15:09:07 +09:00
Ododo
eb1f395101 Fix mapping for #131 and compilation error #139 #132 (related) 2017-10-08 04:00:14 +02:00
Syoyo Fujita
27bdd547f0 If you use tinyobjloader, please let us know via github issue!. 2017-09-25 02:36:15 +09:00
Syoyo Fujita
75a4bd1d35 Add zero-value check when parsing `f' line. Fixes #140. 2017-09-25 02:30:24 +09:00
Syoyo Fujita
7c7335c907 Add test for parsing bump_multipler for normal map. 2017-09-15 16:34:31 +09:00
Syoyo Fujita
3a9483ca6f Add regression test for issue 138. 2017-09-12 02:21:11 +09:00
Syoyo Fujita
1065d7cfb2 Change to add a shape when shape.mesh.indices.size() > 0 once g tag appears. Fixes #138. 2017-09-12 02:18:27 +09:00
Syoyo Fujita
303043f9ec Merge branch 'master' of github.com:syoyo/tinyobjloader 2017-09-11 15:08:39 +09:00
Syoyo Fujita
981f7c5f99 Add VFPR URL. 2017-09-11 14:58:40 +09:00
Syoyo Fujita
dcbc8d51aa Update URL for Rungholt scene. 2017-09-03 12:45:57 +09:00
Syoyo Fujita
785af4491d Add support for parsing map_Bump in mtl. 2017-08-20 18:30:54 +09:00
Syoyo Fujita
be46318a52 print some material infos. 2017-08-08 16:02:12 +09:00
Syoyo Fujita
b5961cd7b1 Merge pull request #133 from pmysiak/patch-1
Update README.md
2017-08-05 15:48:53 +09:00
Peter Myšiak
76632f80b3 Update README.md
Fix typo.
2017-08-04 12:11:36 +02:00
Syoyo Fujita
f59f93d7dc Rename variables to avoid confusion. Fixes #108 . 2017-07-17 18:48:04 +09:00
Syoyo Fujita
1dfd117ccd Add project URLs using tinyobjloader 1.0.x. 2017-07-17 18:40:42 +09:00
Syoyo Fujita
a86b78386b Merge pull request #132 from chrisliebert/master
Added Python mapping from material ID to material name (#131)
2017-07-17 17:21:39 +09:00
chrisliebert
e3508c3ca3 Added mapping from material index to to material name (#131) to Python wrapper. 2017-07-17 01:07:40 -07:00
Syoyo Fujita
8e7da82852 Fix index calculation. 2017-07-10 01:41:39 +09:00
Syoyo Fujita
6cde18eb55 Fix ifdef guard. 2017-07-05 16:50:12 +09:00
Syoyo Fujita
2409832b24 Remove unused file. 2017-07-05 16:32:00 +09:00
Syoyo Fujita
95fba2ab32 Changed to use lfpAlloc from ltalloc for experimental multi-threaded .obj parser since ltalloc is not a porable(e.g. it does not support ARM archtecture). 2017-07-05 16:32:40 +09:00
Syoyo Fujita
99518b6d3e Suppress some clang warnings. 2017-06-05 02:00:32 +09:00
Syoyo Fujita
d8f702c6f7 Merge pull request #128 from sloretz/cppcheck_warnings
Fix Cppcheck warnings
2017-06-03 00:19:51 +09:00
Shane Loretz
6eca09f2bf Removed double import of sstream 2017-06-02 07:31:19 -07:00
Shane Loretz
a1324f17fd Replaced snprintf with stringstream
Deleted now unused TINYOBJ_SSCANF_BUFFER_SIZE
2017-06-02 07:28:20 -07:00
Shane Loretz
56fa047ba9 Replace sscanf with snprintf 2017-06-01 14:14:52 -07:00
Shane Loretz
0f4a955e01 4096 -> TINYOBJ_SSCANF_BUFFER_SIZE 2017-06-01 14:09:15 -07:00
Shane Loretz
fb80e04212 Check sentry to remove unused variable warning 2017-06-01 14:05:03 -07:00
Syoyo Fujita
cdb5c2d375 Fix the number of triangle calculation. Fixes #127 2017-06-02 03:04:42 +09:00
Syoyo Fujita
44bff466e5 Initial support of reflection map(refl). 2017-05-24 17:43:45 +09:00
Syoyo Fujita
47989b591f Update copyright year and version. 2017-05-24 17:22:46 +09:00
Syoyo Fujita
41acdc95bc Merge pull request #126 from alangfel/multiple_texoptions
Deal with more than one texture option
2017-05-24 14:59:56 +09:00
alangfel
cc948e4c44 Deal with more than one texture option
After processing one textureoption like "-s u v w" the next option " -o u v w" has a beginning whitespace. Due to this it does not match to the option "-o" and it is skipped.
2017-05-12 08:34:05 +02:00
Syoyo Fujita
889b2187c1 Add link to Vulkan Cookbook. 2017-05-09 01:23:09 +09:00
Syoyo Fujita
3e146c376c Update README. 2017-04-25 15:50:42 +09:00
Syoyo Fujita
e60d33385e Bump version 1.0.6 2017-04-25 04:34:45 +09:00
Syoyo Fujita
744d2baa58 Merge pull request #125 from noma/upstream_master
Added double support for scientific applications
2017-04-25 04:22:40 +09:00
noma
d5ca258817 Renamed realValues back to flaotValues, as it is part of the external interface and renaming would break existing code. 2017-04-24 17:49:39 +02:00
noma
b1ac3a6c7e Fixed package config and cmake config templates for double variant of the library. 2017-04-24 17:41:22 +02:00
noma
69e56db124 Replaced all float types by real_t ones. Also adapted names accordingly. 2017-04-24 17:31:42 +02:00
noma
13412b0898 Added real_t, defined to float or double depending on CMake option TINYOBJLOADER_USE_DOUBLE 2017-04-24 17:25:21 +02:00
noma
9912bc5023 Added double variant of lib to CMakeLists.txt 2017-04-24 17:20:20 +02:00
Syoyo Fujita
9d9e987c47 Merge pull request #123 from nikitoz/master
Add std namespace for pow, ldexp, sscanf function calls.
2017-02-23 00:35:52 +09:00
nyatsenk
345560040b Add std namespace for pow, ldexp, sscanf function calls. 2017-02-22 11:34:39 +01:00
Syoyo Fujita
9134c1d395 Add file size check. 2017-02-10 17:19:28 +09:00
Syoyo Fujita
cc9897316f Do not exit program when there is no texture coordinate in .obj. 2017-02-09 20:13:27 +09:00
Syoyo Fujita
e43580bd9a Fix build with pre-C++11 compiler 2017-02-09 16:10:19 +09:00
Syoyo Fujita
9613108cef Cosmetics. 2017-02-08 13:58:40 +09:00
Syoyo Fujita
4b29502c82 Add data layout description to README. 2017-02-08 13:57:25 +09:00
Syoyo Fujita
156b709556 Move TINYOBJLOADER_IMPLEMENTATION outside of TINY_OBJ_LOADER_H_ ifdef guard. Fixes #122. 2017-02-02 14:11:13 +09:00
Syoyo Fujita
00f51e3603 Merge pull request #121 from ForsakenHarmony/patch-1
Grammar?
2017-01-11 12:47:13 +09:00
Ashley
da5942d652 Grammar? 2017-01-11 01:10:52 +01:00
Syoyo Fujita
7c3206f919 Ignore Tr parameter when d exists in MTL(#43) 2016-12-31 21:05:37 +09:00
Syoyo Fujita
4886eebbf4 Merge pull request #120 from dPavelDev/master
Fixed error in getting material name in LoadObjWithCallback
2016-12-30 20:17:28 +09:00
dPavelDev
91c727e204 Fixed error in getting material name in LoadObjWithCallback 2016-12-29 15:45:23 +03:00
Syoyo Fujita
26bdacedf6 Merge pull request #119 from jamiesnape/fix-cmake-dir
Add MIT license file, use GNUInstallDirs module, fix cmake directory location
2016-12-29 01:55:00 +09:00
Jamie Snape
7212ee47eb Use GNUInstallDirs module and fix cmake directory location 2016-12-28 11:11:59 -05:00
Jamie Snape
0fe1bb96c2 Add MIT license file 2016-12-28 11:10:07 -05:00
Syoyo Fujita
4bd75baaae Merge pull request #118 from jamiesnape/cleanup
Fix some formatting inconsistencies, fix typo, update minimum CMake
2016-12-21 01:00:16 +09:00
Jamie Snape
bbcfe59c0f Update minimum required version of CMake 2016-12-20 09:44:47 -05:00
Jamie Snape
38c07d34c4 Fix typo in destination of CMake export file 2016-12-20 09:44:26 -05:00
Jamie Snape
2019ace3b7 Remove excess padding around some parentheses in CMake files 2016-12-20 09:32:41 -05:00
Jamie Snape
ad96ff0769 Consistently use spaces instead of tabs in CMake files 2016-12-20 09:32:41 -05:00
Syoyo Fujita
d7f83f29f0 Fix for Windows platform. 2016-12-20 15:42:15 +09:00
Syoyo Fujita
98fad65028 Merge pull request #117 from jamiesnape/cmake-pkg-config
Write and install CMake package config and pkg-config files
2016-12-20 13:56:36 +09:00
Jamie Snape
e88016c63f Write and install pkg-config file 2016-12-19 11:45:00 -05:00
Jamie Snape
edabf19461 Write and install CMake package config files
This allows find_package(tinyobjloader) to be called.
2016-12-19 11:44:39 -05:00
Syoyo Fujita
8bed734a18 Merge branch 'master' of github.com:syoyo/tinyobjloader 2016-12-09 01:51:33 +09:00
Syoyo Fujita
60ffb3ca9a Add missing files. Fixes #115. 2016-12-09 01:51:03 +09:00
Syoyo Fujita
6507e70236 Merge pull request #113 from ReinierMaas/patch-1
Update README.md
2016-12-07 00:55:28 +09:00
Syoyo Fujita
2daec8be53 Search .mtl and texture from .obj's base dir.
Fix bad memory access.
2016-12-07 00:54:12 +09:00
Syoyo Fujita
c2ff3f12fc Support multiple filenames for mtllib line. Fixes #112. 2016-12-06 23:44:55 +09:00
Reinier Maas
a6a134a60e Update README.md
Basedline -> baseline
2016-12-06 15:38:26 +01:00
Syoyo Fujita
e0b39341fc Merge pull request #111 from longjon/python2
Support Python 2.7
2016-12-06 14:37:05 +09:00
Syoyo Fujita
947582b592 Merge pull request #110 from longjon/python-attribs
(Re-)expose attributes to Python
2016-12-06 14:36:14 +09:00
Jonathan L Long
c207ff3561 Support Python 2.7. 2016-12-05 15:24:22 -08:00
Jonathan L Long
41dd7c806e (Re-)expose attribs to Python. 2016-12-05 15:12:28 -08:00
Syoyo Fujita
aa4dabe64f Describe default behavior of mtl_basedir. 2016-11-23 17:17:35 +09:00
Syoyo Fujita
9868630d0e Fix windows build of loader_example. 2016-11-04 12:36:15 +09:00
Syoyo Fujita
f2397573f3 Merge pull request #107 from Warezovvv/master
Little intuitive improvements
2016-11-03 17:39:16 +09:00
Nikita Krupitskas
7d5699118e Little intuitive improvements 2016-11-03 11:23:21 +03:00
Syoyo Fujita
0948ca0417 Add more support for parsing texture options.
Add more unit testing for texture options.
2016-11-03 02:58:44 +09:00
Syoyo Fujita
582eb2b818 Initial support of texture options. 2016-11-02 02:11:17 +09:00
Syoyo Fujita
c2474e27ab Fix seg fault when no material assigned to object in viewer example.
Bump version v1.0.2.
2016-10-24 23:58:33 +09:00
Syoyo Fujita
6c6390f034 Fix typo. 2016-10-24 23:58:23 +09:00
Syoyo Fujita
4d6649cc6d Suppress compiler warnings. 2016-10-24 23:54:20 +09:00
Syoyo Fujita
d543b1447f Merge pull request #105 from dotdash/speedup
Improve parsing speed by about a factor of 2 for large files
2016-10-24 23:37:34 +09:00
Björn Steinbrink
d6eeb14216 Avoid unnecessary ldexp() and pow() calls
Parse times for some large .obj files (without asan):

         File A  File B  File C
Before   1239ms   294ms   271ms
After    1037ms   203ms   190ms
2016-10-24 14:47:59 +02:00
Björn Steinbrink
aa670fe91e Use a lookup table to speed up float parsing
The pow() function is pretty expensive, so creating a small lookup
table for the first few negative powers of ten provides a big speedup.

Parse times for some large .obj files (without asan):

        File A  File B  File C
Before  2500ms   573ms   545ms
After   1239ms   294ms   271ms
2016-10-24 12:15:42 +02:00
Björn Steinbrink
ebdbd8a231 Avoid unnecessary reallocations of the "linebuf" string
safeGetline() already clears the string buffer before writing to it, so
the same buffer can be used multiple times, but the loops calling
safeGetline() have the string scoped within the loop, so its
constructed and destructed in each loop iteration, causing lots of
unnecessary allocations.

Parse times for some large .obj files (without asan):

        File A  File B  File C
Before  2743ms   589ms   615ms
After   2500ms   573ms   545ms
2016-10-24 12:13:56 +02:00
Syoyo Fujita
fed4322d26 Merge branch 'master' of github.com:syoyo/tinyobjloader 2016-10-18 17:34:15 +09:00
Syoyo Fujita
039d4a6c54 Fix a shape is lost if obj ends with a 'usemtl'. Fixes #104 2016-10-18 17:33:28 +09:00
Syoyo Fujita
28ee1b42ce Merge pull request #103 from chrisliebert/master
Issue #74: Added basic diffuse texture support to examples/viewer
2016-10-08 14:02:11 +09:00
Chris Liebert
35889026d6 added additional bounds checking 2016-10-07 21:21:33 -07:00
Chris Liebert
e81ac971b0 Issue #74: Added basic diffuse texture support to examples/viewer using stb_image. The previously used color based on the normal is combined with the diffuse color from the material definition. 2016-10-07 20:58:04 -07:00
Syoyo Fujita
e05ce6aff0 Merge pull request #102 from Entalpi/master
Minor spelling fix
2016-10-07 11:40:33 +09:00
Alexander Lingtorp
e4598ba84a Minor spelling fix 2016-10-06 19:30:21 +02:00
Syoyo Fujita
79513077f3 Fix compilation on pre-C++11 compiler. 2016-10-02 17:37:02 +09:00
Syoyo Fujita
72acadca79 Merge pull request #101 from kavika13/master
Make it easier to use an existing stream reader
2016-10-02 17:35:36 +09:00
Merlyn Morgan-Graham
398e358826 Add unit tests for reading from existing file stream 2016-10-02 01:25:07 -07:00
Merlyn Morgan-Graham
7fc9b0fe97 Add stream based material reader implementation 2016-10-02 00:52:45 -07:00
Merlyn Morgan-Graham
71cc967f42 Allow skipping material reads on LoadObj istream overload 2016-10-02 00:52:19 -07:00
Syoyo Fujita
3ddad1e377 Merge pull request #97 from middlefeng/url-update
Metal viewer URL update.
2016-09-09 00:45:08 +09:00
middleware
92805d3088 Metal viewer URL update. 2016-09-07 06:31:08 -07:00
Syoyo Fujita
60acd05a03 Add brief README. 2016-09-06 02:18:24 +09:00
Syoyo Fujita
4a18e241d9 Measure zstd decompress time. 2016-09-06 02:11:23 +09:00
Syoyo Fujita
1b88a1e3c7 Support reading .obj from ZStd compressed format. 2016-09-04 19:34:05 +09:00
Syoyo Fujita
b3feefafdf Add link to MetalExamples. 2016-09-03 21:43:00 +09:00
Syoyo Fujita
a7a16db908 Add a link to GeeXLab. 2016-08-23 02:48:06 +09:00
Syoyo Fujita
9f92ba34a6 Update Feature list. 2016-08-23 02:44:32 +09:00
Syoyo Fujita
25cf039953 Add more link. 2016-08-23 02:37:47 +09:00
Syoyo Fujita
6bf145d7cf Add link to "Fast OBJ file importing and parsing in CUDA". 2016-08-23 02:35:31 +09:00
Syoyo Fujita
69240e18b4 Add link to PBGI. 2016-08-23 02:29:41 +09:00
Syoyo Fujita
5b9f431512 Update TODO list. 2016-08-20 18:16:50 +09:00
Syoyo Fujita
ad79762212 Update README. 2016-08-20 18:03:18 +09:00
Syoyo Fujita
64149943cc Add link to examples. 2016-08-20 18:01:27 +09:00
Syoyo Fujita
714194d353 Merge branch 'master' of github.com:syoyo/tinyobjloader 2016-08-20 17:58:57 +09:00
Syoyo Fujita
9d81c24934 Update AppVeyor script. 2016-08-20 17:54:24 +09:00
Syoyo Fujita
25c194bf71 Update README. 2016-08-20 17:53:07 +09:00
Syoyo Fujita
5a4c5ff668 Merge branch 'develop' 2016-08-20 17:49:59 +09:00
Syoyo Fujita
f06e814d7c Update README. 2016-08-20 16:23:41 +09:00
Syoyo Fujita
5eef2b0914 Fix python binding. 2016-08-20 16:23:20 +09:00
Syoyo Fujita
49988672f4 Add link to tinyobjloader-c. 2016-08-19 20:22:26 +09:00
Syoyo Fujita
d192402800 Support Tf in MTL. 2016-08-19 20:19:28 +09:00
Syoyo Fujita
646f1312f1 Parse 'Tf' field in MTL. 2016-08-18 16:13:27 +09:00
Syoyo Fujita
db62a6c1cc Merge pull request #95 from graysonlang/patch-1
Fix MTL token for transmission filter.
2016-08-18 11:49:51 +09:00
Grayson Lang
8e53519a27 Ooops, meant "Tf" not "TF". 2016-08-17 13:34:18 -07:00
Grayson Lang
d3d6932efd Fix MTL "transmission filter" token
The "transmission filter" is currently set to Kt, which is undocumented. Adding support for the specified token of "Tf".
2016-08-17 13:30:25 -07:00
Syoyo Fujita
dea325cdcb Fix face num calculation. 2016-08-13 19:27:13 +09:00
Syoyo Fujita
2b50b31657 Return parsed material information in parseObj API..
Parse PBR extension in MTL
2016-08-13 18:38:45 +09:00
Syoyo Fujita
110b49a0c8 Rename vertex_index struct. 2016-08-13 15:27:35 +09:00
Syoyo Fujita
319746d3db Fix parsing benchmark flag. 2016-08-13 15:09:58 +09:00
Syoyo Fujita
2cb73fa85d Fix the ordefing of a constructor call of vertex_index. 2016-08-13 02:52:36 +09:00
Syoyo Fujita
5a832b470a Update README. 2016-08-12 23:13:31 +09:00
Syoyo Fujita
42f04024d4 Remove old version log. 2016-08-12 23:13:05 +09:00
Syoyo Fujita
07852e206d Apply clang-format. 2016-08-12 23:12:46 +09:00
Syoyo Fujita
156b47760d Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-08-12 20:40:16 +09:00
Syoyo Fujita
673501749f Apply clang-format. 2016-08-12 20:39:42 +09:00
Syoyo Fujita
b56fc1a0cc Fix appveyor script. 2016-08-12 19:01:51 +09:00
Syoyo Fujita
2ed3222bbe Compute geometric normal where vertex normal is not available. 2016-08-12 18:58:34 +09:00
Syoyo Fujita
c7da23795d Add static keyword to safeGetline(). 2016-08-05 19:16:46 +09:00
Syoyo Fujita
8ca2bc0de7 Fix appveyor script. 2016-08-02 17:14:46 +09:00
Syoyo Fujita
0a85945767 Skip trailing whitespace in mtl. Fixes #92. 2016-08-02 17:04:00 +09:00
Syoyo Fujita
51d13700d8 Skip trailing whitespace in mtl. Fixes #92. 2016-08-02 16:55:50 +09:00
Syoyo Fujita
1983e889dc Update callback API example.
Update API document.
2016-07-28 16:21:48 +09:00
Syoyo Fujita
dfe9d7bcae Merge pull request #91 from adishavit/develop
Changes the value indicating non-existent index to 0.
2016-07-28 16:16:38 +09:00
Adi Shavit @ MacBookPro
4dee4cc673 Changes the value indicating non-existent index to 0. OBJ indices are 1 (or -1) based, so 0 is an invalid value. 2016-07-28 10:12:16 +03:00
Syoyo Fujita
a7ea651bef Suppress clang warnings. 2016-07-28 00:30:52 +09:00
Syoyo Fujita
4c2afb8814 Merge pull request #90 from adishavit/develop
Changes the LoadObjWithCallback() API
2016-07-27 17:45:49 +09:00
Adi Shavit @ MacBookPro
951833812a Changes the LoadObjWithCallback() API to accept std::istream& instead of pointed since this is a required argument.
- Also changing the argument order to allow for defaults for optional arguments.
2016-07-27 11:38:25 +03:00
Syoyo Fujita
e456cc949d Merge pull request #89 from adishavit/develop
Crash bug fix + optimizations in LoadObjWithCallback()
2016-07-27 16:30:36 +09:00
Syoyo Fujita
75e64cd47a Support parsing w element of vertex coordinate, and also third element of texture coordinates. Fixes #88. 2016-07-27 16:16:51 +09:00
Adi Shavit @ MacBookPro
3736a5791f Fix a crash bug in LoadObjWithCallback() when passing a nullptr as MaterialReader *readMatFn.
- This preserves the existing API. If `nullptr` is passed then the material file will be ignored. This is useful when the user is not interested in the materials.
- Note that if `nullptr` is not a valid option for this function, then the API needs to be changed to take `MaterialReader&`.
2016-07-27 10:04:22 +03:00
Adi Shavit @ MacBookPro
0b0bf60137 Move heap-based objects like vectors and strings outside the parse loop in LoadObjWithCallback().
This avoids reallocation on every use making the code faster.
2016-07-27 10:00:13 +03:00
Syoyo Fujita
d496d8eab6 Remove some invalid comments. Fix calling index_cb per f line. Fixes #87. 2016-07-27 00:02:53 +09:00
Syoyo Fujita
22883def8d Support PBR extension for MTL which is proposed in http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr 2016-07-25 22:46:30 +09:00
Syoyo Fujita
5826f1e149 Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-07-25 19:03:42 +09:00
Syoyo Fujita
ef6560298e Add Vulkan Tutorial to the list. 2016-07-25 19:02:51 +09:00
Syoyo Fujita
e3a56816d6 Use std::getline() to read arbitrary size of line data. 2016-07-24 15:53:05 +09:00
Syoyo Fujita
5ef400882a Fix pow computation. 2016-07-15 13:25:44 +09:00
Syoyo Fujita
333bb55d84 Revert memcpy'ing input string into local buffer. 2016-07-15 02:01:50 +09:00
Syoyo Fujita
7d6318c3ad Remove redundant & buggy memcpy.
Add verbose option.
2016-07-15 01:38:39 +09:00
Syoyo Fujita
d4a7eefc54 Fix typo in usage. 2016-07-10 00:11:37 +09:00
Syoyo Fujita
d2793bf454 Update performance note. 2016-07-09 01:31:13 +09:00
Syoyo Fujita
d5c722125a Show parsing time. 2016-07-09 00:52:27 +09:00
Syoyo Fujita
16ed0ac129 Update README. 2016-07-06 01:36:16 +09:00
Syoyo Fujita
b8c33156de Update README. 2016-07-01 23:39:36 +09:00
Syoyo Fujita
0389e23847 Show parsing time. 2016-07-01 23:35:39 +09:00
Syoyo Fujita
e85155b2dd Add README on optimized obj loader. 2016-06-28 00:39:36 +09:00
Syoyo Fujita
164dcb8121 Refactor. 2016-06-11 19:34:12 +09:00
Syoyo Fujita
5fc9842e97 Refactor source code of optimized .obj parser. 2016-06-07 18:58:08 +09:00
Syoyo Fujita
831a1a4b8d Initial support of shape data structure and material ids. 2016-06-06 21:22:38 +09:00
Syoyo Fujita
4b9ef527c6 Parallelize merge. 2016-06-01 01:07:14 +09:00
Syoyo Fujita
b69d2a2c55 Add more links. 2016-05-29 16:37:30 +09:00
Syoyo Fujita
629f1825c5 Support retina resolution. 2016-05-29 16:30:54 +09:00
Syoyo Fujita
e210379335 Add Probulator 2016-05-29 14:08:27 +09:00
Syoyo Fujita
659976b8f3 Merge branch 'master' of github.com:syoyo/tinyobjloader 2016-05-29 13:32:24 +09:00
Syoyo Fujita
96ba498d70 Add voxelizer. 2016-05-29 13:09:00 +09:00
Syoyo Fujita
5f4a557d69 Fix memory bug. 2016-05-25 19:48:25 +09:00
Syoyo Fujita
2c7ba7b2ab Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-05-25 19:06:42 +09:00
Syoyo Fujita
de79540879 Parse material name. 2016-05-24 13:37:13 +09:00
Syoyo Fujita
8880438c36 Optimzie face generation. 2016-05-24 12:58:31 +09:00
Syoyo Fujita
8c03771aac Add ltalloc. 2016-05-19 15:05:57 +09:00
Syoyo Fujita
fc42eb8232 Merge pull request #83 from filipwasil/ReadmeFix
missing size() in radme
2016-05-16 13:31:49 +09:00
Syoyo Fujita
da5d9b1e1c Merge pull request #82 from filipwasil/develop
Enable building as shared library
2016-05-16 13:31:09 +09:00
filipwasil
64164b3a82 missing size() in radme 2016-05-15 22:26:29 +02:00
Syoyo Fujita
8205067928 Support loading .obj from gzip compression. 2016-05-16 01:24:52 +09:00
filipwasil
660cc22b74 Enable building as shared library 2016-05-15 15:47:55 +02:00
Syoyo Fujita
00251e9a5b Remove Makefile. 2016-05-15 19:19:41 +09:00
Syoyo Fujita
54c28bd05f Fix vertex_index creation. 2016-05-15 19:18:21 +09:00
Syoyo Fujita
d392282f02 Fix parser. 2016-05-15 18:49:06 +09:00
Syoyo Fujita
88fe2421d9 Add gl view for testing. 2016-05-15 17:46:59 +09:00
Syoyo Fujita
7ecb0b2f37 Use sefe getline for files with different line breaks. Fixes #81. 2016-05-15 16:20:35 +09:00
Syoyo Fujita
566d259df2 Specify # of threads. 2016-05-15 16:08:16 +09:00
Syoyo Fujita
654e686079 Optimized a bit. 2016-05-14 17:25:36 +09:00
Syoyo Fujita
bf626b5809 Mostly finished parallelized parsing of .obj. Still work in progress. 2016-05-14 16:53:55 +09:00
Syoyo Fujita
db62284cef Optimized more. 2016-05-14 12:33:12 +09:00
Syoyo Fujita
a14bbdb065 Merge pull request #80 from Vazquinhos/master
Fixing errors normal generation no triangulation. Remove warnings. Coding Style.
2016-05-13 21:18:48 +09:00
Vazquinhos
bfedfbb1fb Merge remote-tracking branch 'refs/remotes/syoyo/master'
# Conflicts:
#	tiny_obj_loader.h
2016-05-13 14:03:03 +02:00
Syoyo Fujita
109090e5b8 Optimized parser more(not working yet, though) 2016-05-13 21:00:03 +09:00
Vazquinhos
41f46c7fd7 Error fixed with no triangulation. Removed warnings and modified coding brace style 2016-05-13 13:54:27 +02:00
Vazquinhos
a62dd278e2 Merge remote-tracking branch 'refs/remotes/syoyo/master' 2016-05-13 13:19:09 +02:00
Syoyo Fujita
73d823ba77 Add code for parallel optimized .obj parsing(not working yet). 2016-05-13 19:49:54 +09:00
Syoyo Fujita
2d16510c15 Measure .obj parsing time. 2016-05-13 16:33:40 +09:00
Syoyo Fujita
a58a804850 Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-05-13 15:56:45 +09:00
Syoyo Fujita
93c495eca8 Fix 'o' callback. 2016-05-13 15:56:12 +09:00
Syoyo Fujita
1a4e018053 Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-05-12 19:40:26 +09:00
Syoyo Fujita
d3fbf6bb7b Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-05-12 19:38:48 +09:00
Syoyo Fujita
0a3d47fdad Update README. 2016-05-12 19:38:29 +09:00
Syoyo Fujita
73af05bc23 Add assertion check. 2016-05-12 19:33:22 +09:00
Syoyo Fujita
bbb6aeff6a Adjust near/far clipping value. 2016-05-12 02:57:41 +09:00
Syoyo Fujita
48839e3b07 Add screenshot of glviewer. 2016-05-12 01:13:47 +09:00
Syoyo Fujita
e9a7c76c23 Add build script for Windows.
Fix build on Windows.
2016-05-11 23:38:36 +09:00
Syoyo Fujita
b90f767367 Cosmetics. 2016-05-02 02:03:51 +09:00
Syoyo Fujita
368312cb4b Fix index buffer was not filled when !triangulate case.
Suppress VS2015 warnings.
Update premake5.exe.
2016-05-02 01:42:18 +09:00
Syoyo Fujita
be1ba58aec Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-05-01 21:49:57 +09:00
Syoyo Fujita
8d60b4963a Rename varialble for better understanding.
Write some API usage in README.md.
2016-05-01 21:30:50 +09:00
Syoyo Fujita
5c121140e6 Merge pull request #76 from skurmedel/develop
viewer: Added initial Makefile support for mingw64 (windows)
2016-04-27 10:56:00 +09:00
unknown
7dc1418e2b viewer: Cleaned up Makefile and added a semblance of a Mingw64-target for Windows. 2016-04-26 19:42:42 +02:00
Syoyo Fujita
9d6b58b90e Add new build.ninja. 2016-04-24 00:34:05 +09:00
Syoyo Fujita
58fa260605 Show normal vector in viewer example. 2016-04-20 16:00:45 +09:00
Syoyo Fujita
7399aedfdd Initial support of linux for viewer example. 2016-04-19 20:34:51 +09:00
Syoyo Fujita
28fc3523d4 Disable coveralls due to Travis + python bug? 2016-04-19 14:46:23 +09:00
Syoyo Fujita
a608c3b5b1 Update python. 2016-04-19 14:37:57 +09:00
Syoyo Fujita
2e6cccbfe4 Force use g++ for pip install. 2016-04-19 14:32:10 +09:00
Syoyo Fujita
a66eab0f75 More Travis fix. 2016-04-19 14:03:43 +09:00
Syoyo Fujita
170cb86870 Change to sudo required. 2016-04-19 13:56:27 +09:00
Syoyo Fujita
016362234b Update Travis script. 2016-04-19 13:36:46 +09:00
Syoyo Fujita
28d1bb5521 Update Travis. 2016-04-19 13:32:03 +09:00
Syoyo Fujita
045d31eb7a Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-04-19 13:28:16 +09:00
Syoyo Fujita
9eecb4634d Update Travis script. 2016-04-19 13:27:44 +09:00
Syoyo Fujita
6b41e68bbc Install ninja in appveyor build. 2016-04-19 13:25:57 +09:00
Syoyo Fujita
a55247574c Suppress VC2013 warnings.
Update AppVeyor script.
2016-04-19 13:11:55 +09:00
Syoyo Fujita
f4695de408 Suppress compiler warning. 2016-04-19 12:50:41 +09:00
Syoyo Fujita
00ed158a8e Update CMake. 2016-04-19 12:32:12 +09:00
Syoyo Fujita
ec5df8a48f Merge branch 'develop' of github.com:syoyo/tinyobjloader into develop 2016-04-18 20:07:48 +09:00
Syoyo Fujita
1703ab087d Add simple OpenGL viewer example. 2016-04-18 20:07:04 +09:00
Syoyo Fujita
153de2b3f0 Update Android build. 2016-04-18 19:29:59 +09:00
Syoyo Fujita
90d33c33c0 Fix CI scripts. 2016-04-18 17:59:17 +09:00
Syoyo Fujita
1e663342bf Add callback API example.
Fix a sentinel value for the vertex index.
2016-04-18 17:52:04 +09:00
Syoyo Fujita
93acf63157 Change API for usemtl callback. 2016-04-18 16:48:37 +09:00
Syoyo Fujita
72ef6cbb76 Add initial unit test codes using Catch.
Add Kuroga build script.
2016-04-18 16:03:24 +09:00
Syoyo Fujita
54bd46014c Use google C++ code style. 2016-04-16 20:25:53 +09:00
Syoyo Fujita
ee7d6cc0fd Refactor and re-design tinyobjloader.
* Separete attribs(vtx,normal,texcoords) and shape.
* Support different index for vtx/normal/texcoord.
2016-04-16 19:49:12 +09:00
107 changed files with 36264 additions and 1331 deletions

View File

@@ -1,5 +1,5 @@
--- ---
BasedOnStyle: LLVM BasedOnStyle: Google
IndentWidth: 2 IndentWidth: 2
TabWidth: 2 TabWidth: 2
UseTab: Never UseTab: Never

View File

@@ -1,5 +1,5 @@
language: cpp language: cpp
sudo: false sudo: required
matrix: matrix:
include: include:
- addons: &1 - addons: &1
@@ -36,21 +36,17 @@ matrix:
env: COMPILER_VERSION=4.9 BUILD_TYPE=Release env: COMPILER_VERSION=4.9 BUILD_TYPE=Release
- addons: *1 - addons: *1
compiler: clang compiler: clang
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0 --coverage" CXXFLAGS="-O0 env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug
--coverage" REPORT_COVERAGE=1
before_install: before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi
- if [ -n "$REPORT_COVERAGE" ]; then pip install --user cpp-coveralls; fi - if [ -n "$REPORT_COVERAGE" ]; then sudo apt-get update python; fi
- if [ -n "$REPORT_COVERAGE" ]; then sudo apt-get install python-dev libffi-dev libssl-dev; fi
- if [ -n "$REPORT_COVERAGE" ]; then sudo pip install --upgrade pip; fi
- if [ -n "$REPORT_COVERAGE" ]; then CXX=g++ pip install --user requests[security]; fi
- if [ -n "$REPORT_COVERAGE" ]; then CXX=g++ pip install --user cpp-coveralls; fi
script: script:
- mkdir build && cd build - cd tests
- export CC="${CC}-${COMPILER_VERSION}" - make check
- export CXX="${CXX}-${COMPILER_VERSION}"
- ${CC} -v
- cmake --version
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DTINYOBJLOADER_BUILD_TEST_LOADER=On -G Ninja
..
- ninja
- ./test_loader ../cornell_box.obj
- if [ -n "$REPORT_COVERAGE" ]; then coveralls -b . -r .. -e examples -e tools -e - if [ -n "$REPORT_COVERAGE" ]; then coveralls -b . -r .. -e examples -e tools -e
jni -e python -e images -E ".*CompilerId.*" -E ".*feature_tests.*" ; fi jni -e python -e images -E ".*CompilerId.*" -E ".*feature_tests.*" ; fi
- cd .. - cd ..

View File

@@ -2,57 +2,145 @@
#This configures the Cmake system with multiple properties, depending #This configures the Cmake system with multiple properties, depending
#on the platform and configuration it is set to build in. #on the platform and configuration it is set to build in.
project(tinyobjloader) project(tinyobjloader)
cmake_minimum_required(VERSION 2.8.6) cmake_minimum_required(VERSION 2.8.11)
set(TINYOBJLOADER_SOVERSION 1)
set(TINYOBJLOADER_VERSION 1.0.4)
#optional double precision support
option(TINYOBJLOADER_USE_DOUBLE "Build library with double precision instead of single (float)" OFF)
if(TINYOBJLOADER_USE_DOUBLE)
add_definitions(-DTINYOBJLOADER_USE_DOUBLE)
set(LIBRARY_NAME ${PROJECT_NAME}_double)
else()
set(LIBRARY_NAME ${PROJECT_NAME})
endif()
#Folder Shortcuts #Folder Shortcuts
set(TINYOBJLOADEREXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples) set(TINYOBJLOADEREXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples)
set(tinyobjloader-Source set(tinyobjloader-Source
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.h ${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.h
${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.cc ${CMAKE_CURRENT_SOURCE_DIR}/tiny_obj_loader.cc
) )
set(tinyobjloader-Test-Source set(tinyobjloader-Example-Source
${CMAKE_CURRENT_SOURCE_DIR}/test.cc ${CMAKE_CURRENT_SOURCE_DIR}/loader_example.cc
) )
set(tinyobjloader-examples-objsticher set(tinyobjloader-examples-objsticher
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.h ${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.h
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.cc ${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_writer.cc
${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_sticher.cc ${TINYOBJLOADEREXAMPLES_DIR}/obj_sticher/obj_sticher.cc
) )
add_library(tinyobjloader #Install destinations
${tinyobjloader-Source} include(GNUInstallDirs)
)
option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Test Loader Application" OFF) set(TINYOBJLOADER_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME}/cmake)
set(TINYOBJLOADER_DOC_DIR ${CMAKE_INSTALL_DOCDIR})
set(TINYOBJLOADER_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(TINYOBJLOADER_LIBRARY_DIR ${CMAKE_INSTALL_LIBDIR})
set(TINYOBJLOADER_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
set(TINYOBJLOADER_RUNTIME_DIR ${CMAKE_INSTALL_BINDIR})
option(TINYOBJLOADER_BUILD_TEST_LOADER "Build Example Loader Application" OFF)
option(TINYOBJLOADER_COMPILATION_SHARED "Build as shared library" OFF)
if(TINYOBJLOADER_COMPILATION_SHARED)
add_library(${LIBRARY_NAME} SHARED ${tinyobjloader-Source})
set_target_properties(${LIBRARY_NAME} PROPERTIES
SOVERSION ${TINYOBJLOADER_SOVERSION}
)
else()
add_library(${LIBRARY_NAME} STATIC ${tinyobjloader-Source})
endif()
set_target_properties(${LIBRARY_NAME} PROPERTIES VERSION ${TINYOBJLOADER_VERSION})
target_include_directories(${LIBRARY_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${TINYOBJLOADER_INCLUDE_DIR}>
)
export(TARGETS ${LIBRARY_NAME} FILE ${PROJECT_NAME}-targets.cmake)
if(TINYOBJLOADER_BUILD_TEST_LOADER) if(TINYOBJLOADER_BUILD_TEST_LOADER)
add_executable(test_loader ${tinyobjloader-Test-Source}) add_executable(test_loader ${tinyobjloader-Example-Source})
target_link_libraries(test_loader tinyobjloader) target_link_libraries(test_loader ${LIBRARY_NAME})
endif() endif()
option(TINYOBJLOADER_BUILD_OBJ_STICHER "Build OBJ Sticher Application" OFF) option(TINYOBJLOADER_BUILD_OBJ_STICHER "Build OBJ Sticher Application" OFF)
if (TINYOBJLOADER_BUILD_OBJ_STICHER) if(TINYOBJLOADER_BUILD_OBJ_STICHER)
add_executable(obj_sticher ${tinyobjloader-examples-objsticher}) add_executable(obj_sticher ${tinyobjloader-examples-objsticher})
target_link_libraries(obj_sticher tinyobjloader) target_link_libraries(obj_sticher ${LIBRARY_NAME})
install ( TARGETS install(TARGETS
obj_sticher obj_sticher
DESTINATION DESTINATION
bin ${TINYOBJLOADER_RUNTIME_DIR}
) )
endif() endif()
#Installation #Write CMake package config files
install ( TARGETS include(CMakePackageConfigHelpers)
tinyobjloader
DESTINATION configure_package_config_file(
lib ${PROJECT_NAME}-config.cmake.in
${LIBRARY_NAME}-config.cmake
INSTALL_DESTINATION
${TINYOBJLOADER_CMAKE_DIR}
PATH_VARS
TINYOBJLOADER_INCLUDE_DIR
TINYOBJLOADER_LIBRARY_DIR
NO_CHECK_REQUIRED_COMPONENTS_MACRO
) )
install ( FILES
write_basic_package_version_file(${LIBRARY_NAME}-config-version.cmake
VERSION
${TINYOBJLOADER_VERSION}
COMPATIBILITY
SameMajorVersion
)
#pkg-config file
configure_file(${PROJECT_NAME}.pc.in ${LIBRARY_NAME}.pc @ONLY)
#Installation
install(TARGETS
${LIBRARY_NAME}
EXPORT ${PROJECT_NAME}-targets
DESTINATION
${TINYOBJLOADER_LIBRARY_DIR}
PUBLIC_HEADER DESTINATION
${TINYOBJLOADER_INCLUDE_DIR}
RUNTIME DESTINATION
${TINYOBJLOADER_RUNTIME_DIR}
)
install(EXPORT
${PROJECT_NAME}-targets
DESTINATION
${TINYOBJLOADER_CMAKE_DIR}
)
install(FILES
tiny_obj_loader.h tiny_obj_loader.h
DESTINATION DESTINATION
include ${TINYOBJLOADER_INCLUDE_DIR}
)
install(FILES
LICENSE
DESTINATION
${TINYOBJLOADER_DOC_DIR}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}-config-version.cmake"
DESTINATION
${TINYOBJLOADER_CMAKE_DIR}
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}.pc"
DESTINATION
${TINYOBJLOADER_PKGCONFIG_DIR}
) )

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2012-2016 Syoyo Fujita and many contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

295
README.md
View File

@@ -1,5 +1,4 @@
tinyobjloader # tinyobjloader
=============
[![Join the chat at https://gitter.im/syoyo/tinyobjloader](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/syoyo/tinyobjloader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/syoyo/tinyobjloader](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/syoyo/tinyobjloader?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -11,45 +10,58 @@ tinyobjloader
[![Coverage Status](https://coveralls.io/repos/github/syoyo/tinyobjloader/badge.svg?branch=master)](https://coveralls.io/github/syoyo/tinyobjloader?branch=master) [![Coverage Status](https://coveralls.io/repos/github/syoyo/tinyobjloader/badge.svg?branch=master)](https://coveralls.io/github/syoyo/tinyobjloader?branch=master)
http://syoyo.github.io/tinyobjloader/ [https://github.com/syoyo/tinyobjloader](https://github.com/syoyo/tinyobjloader)
Tiny but powerful 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 powerful single file wavefront obj loader written in C++. No dependency except for C++ STL. It can parse over 10M polygons with moderate memory and time.
`tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-) `tinyobjloader` is good for embedding .obj loader to your (global illumination) renderer ;-)
If you are looking for C89 version, please see https://github.com/syoyo/tinyobjloader-c .
What's new Notice!
----------
* Mar 13, 2016 : Introduce `load_flag_t` and flat normal calculation flag! Thanks Vazquinhos!
* Jan 29, 2016 : Support n-polygon(no triangulation) and OpenSubdiv crease tag! Thanks dboogert!
* Nov 26, 2015 : Now single-header only!.
* Nov 08, 2015 : Improved API.
* 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!
* 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 21, 2014 : Define default material if no material definition exists in .obj. Thanks YarmUI!
* Apr 10, 2014 : Add support for parsing 'illum' and 'd'/'Tr' statements. Thanks mmp!
* Jan 27, 2014 : Added CMake project. Thanks bradc6!
* Nov 26, 2013 : Performance optimization by NeuralSandwich. 9% improvement in his project, thanks!
* Sep 12, 2013 : Added multiple .obj sticher example.
Example
------- -------
![Rungholt](https://github.com/syoyo/tinyobjloader/blob/master/images/rungholt.jpg?raw=true) We have released new version v1.0.0 on 20 Aug, 2016.
Old version is available `v0.9.x` branch https://github.com/syoyo/tinyobjloader/tree/v0.9.x
## What's new
* 20 Aug, 2016 : Bump version v1.0.0. New data structure and API!
### Old version
Previous old version is avaiable in `v0.9.x` branch.
## Example
![Rungholt](images/rungholt.jpg)
tinyobjloader can successfully load 6M triangles Rungholt scene. tinyobjloader can successfully load 6M triangles Rungholt scene.
http://graphics.cs.williams.edu/data/meshes.xml http://casual-effects.com/data/index.html
Use case ![](images/sanmugel.png)
--------
* [examples/viewer/](examples/viewer) OpenGL .obj viewer
* [examples/callback_api/](examples/callback_api/) Callback API example
* [examples/voxelize/](examples/voxelize/) Voxelizer example
## Use case
TinyObjLoader is successfully used in ... TinyObjLoader is successfully used in ...
### New version(v1.0.x)
* Double precision support through `TINYOBJLOADER_USE_DOUBLE` thanks to noma
* Loading models in Vulkan Tutorial https://vulkan-tutorial.com/Loading_models
* .obj viewer with Metal https://github.com/middlefeng/NuoModelViewer/tree/master
* Vulkan Cookbook https://github.com/PacktPublishing/Vulkan-Cookbook
* cudabox: CUDA Solid Voxelizer Engine https://github.com/gaspardzoss/cudavox
* Drake: A planning, control, and analysis toolbox for nonlinear dynamical systems https://github.com/RobotLocomotion/drake
* VFPR - a Vulkan Forward Plus Renderer : https://github.com/WindyDarian/Vulkan-Forward-Plus-Renderer
* Your project here! (Letting us know via github issue is welcome!)
### Old version(v0.9.x)
* bullet3 https://github.com/erwincoumans/bullet3 * bullet3 https://github.com/erwincoumans/bullet3
* pbrt-v2 https://github.com/mmp/pbrt-v2 * pbrt-v2 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
@@ -61,111 +73,140 @@ TinyObjLoader is successfully used in ...
* pbrt-v3 https://github.com/mmp/pbrt-v3 * pbrt-v3 https://github.com/mmp/pbrt-v3
* cocos2d-x https://github.com/cocos2d/cocos2d-x/ * cocos2d-x https://github.com/cocos2d/cocos2d-x/
* Android Vulkan demo https://github.com/SaschaWillems/Vulkan * Android Vulkan demo https://github.com/SaschaWillems/Vulkan
* Your project here! * voxelizer https://github.com/karimnaaji/voxelizer
* Probulator https://github.com/kayru/Probulator
* OptiX Prime baking https://github.com/nvpro-samples/optix_prime_baking
* FireRays SDK https://github.com/GPUOpen-LibrariesAndSDKs/FireRays_SDK
* parg, tiny C library of various graphics utilities and GL demos https://github.com/prideout/parg
* Opengl unit of ChronoEngine https://github.com/projectchrono/chrono-opengl
* Point Based Global Illumination on modern GPU https://pbgi.wordpress.com/code-source/
* Fast OBJ file importing and parsing in CUDA http://researchonline.jcu.edu.au/42515/1/2015.CVM.OBJCUDA.pdf
* Sorted Shading for Uni-Directional Pathtracing by Joshua Bainbridge https://nccastaff.bournemouth.ac.uk/jmacey/MastersProjects/MSc15/02Josh/joshua_bainbridge_thesis.pdf
* GeeXLab http://www.geeks3d.com/hacklab/20160531/geexlab-0-12-0-0-released-for-windows/
Features
-------- ## Features
* Group(parse multiple group name) * Group(parse multiple group name)
* Vertex * Vertex
* Vertex color(as an extension: https://blender.stackexchange.com/questions/31997/how-can-i-get-vertex-painted-obj-files-to-import-into-blender)
* Texcoord * Texcoord
* Normal * Normal
* Material * Material
* Unknown material attributes are returned as key-value(value is string) map. * Unknown material attributes are returned as key-value(value is string) map.
* Crease tag('t'). This is OpenSubdiv specific(not in wavefront .obj specification) * Crease tag('t'). This is OpenSubdiv specific(not in wavefront .obj specification)
* PBR material extension for .MTL. Its proposed here: http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
* Callback API for custom loading.
* Double precision support(for HPC application).
* Smoothing group
TODO ## TODO
----
* [ ] Support different indices for vertex/normal/texcoord * [ ] Fix obj_sticker example.
* [ ] More unit test codes.
* [x] Texture options
License ## License
-------
Licensed under 2 clause BSD. Licensed under MIT license.
Usage ## Usage
-----
TinyObjLoader triangulate input .obj by default. ### Data format
```c++
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
#include "tiny_obj_loader.h"
std::string inputfile = "cornell_box.obj"; `attrib_t` contains single and linear array of vertex data(position, normal and texcoord).
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err; ```
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str()); attrib_t::vertices => 3 floats per vertex
if (!err.empty()) { // `err` may contain warning message. v[0] v[1] v[2] v[3] v[n-1]
std::cerr << err << std::endl; +-----------+-----------+-----------+-----------+ +-----------+
} | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
+-----------+-----------+-----------+-----------+ +-----------+
if (!ret) { attrib_t::normals => 3 floats per vertex
exit(1);
}
std::cout << "# of shapes : " << shapes.size() << std::endl; n[0] n[1] n[2] n[3] n[n-1]
std::cout << "# of materials : " << materials.size() << std::endl; +-----------+-----------+-----------+-----------+ +-----------+
| x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
+-----------+-----------+-----------+-----------+ +-----------+
for (size_t i = 0; i < shapes.size(); i++) { attrib_t::texcoords => 2 floats per vertex
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].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size()); t[0] t[1] t[2] t[3] t[n-1]
assert((shapes[i].mesh.positions.size() % 3) == 0); +-----------+-----------+-----------+-----------+ +-----------+
for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) { | u | v | u | v | u | v | u | v | .... | u | v |
printf(" v[%ld] = (%f, %f, %f)\n", v, +-----------+-----------+-----------+-----------+ +-----------+
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1], attrib_t::colors => 3 floats per vertex(vertex color. optional)
shapes[i].mesh.positions[3*v+2]);
} 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 |
+-----------+-----------+-----------+-----------+ +-----------+
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", materials[i].dissolve);
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
``` ```
Reading .obj without triangulation. Use `num_vertices[i]` to iterate over faces(indices). `num_vertices[i]` stores the number of vertices for ith face. 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) |
+----+----+----+----+----+----+----+----+----+----+ +--------+--------+--------+
```
Note that when `triangulate` flas is true in `tinyobj::LoadObj()` argument, `num_face_vertices` are all filled with 3(triangle).
### float data type
TinyObjLoader now use `real_t` for floating point data type.
Default is `float(32bit)`.
You can enable `double(64bit)` precision by using `TINYOBJLOADER_USE_DOUBLE` define.
#### Example code
```c++ ```c++
#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc #define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
#include "tiny_obj_loader.h" #include "tiny_obj_loader.h"
std::string inputfile = "cornell_box.obj"; std::string inputfile = "cornell_box.obj";
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::string err; std::string err;
int flags = 1; // see load_flags_t enum for more information. bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, inputfile.c_str());
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str(), flags);
if (!err.empty()) { // `err` may contain warning message. if (!err.empty()) { // `err` may contain warning message.
std::cerr << err << std::endl; std::cerr << err << std::endl;
@@ -175,21 +216,53 @@ if (!ret) {
exit(1); exit(1);
} }
for (size_t i = 0; i < shapes.size(); i++) { // Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) {
size_t indexOffset = 0; // Loop over faces(polygon)
for (size_t n = 0; n < shapes[i].mesh.num_vertices.size(); n++) { size_t index_offset = 0;
int ngon = shapes[i].mesh.num_vertices[n]; for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
for (size_t f = 0; f < ngon; f++) { int fv = shapes[s].mesh.num_face_vertices[f];
unsigned int v = shapes[i].mesh.indices[indexOffset + f];
printf(" face[%ld] v[%ld] = (%f, %f, %f)\n", n,
shapes[i].mesh.positions[3*v+0],
shapes[i].mesh.positions[3*v+1],
shapes[i].mesh.positions[3*v+2]);
// 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];
// Optional: vertex colors
// tinyobj::real_t red = attrib.colors[3*idx.vertex_index+0];
// tinyobj::real_t green = attrib.colors[3*idx.vertex_index+1];
// tinyobj::real_t blue = attrib.colors[3*idx.vertex_index+2];
} }
indexOffset += ngon; index_offset += fv;
}
// per-face material
shapes[s].mesh.material_ids[f];
}
} }
``` ```
## Optimized loader
Optimized multi-threaded .obj loader is available at `experimental/` directory.
If you want absolute performance to load .obj data, this optimized loader will fit your purpose.
Note that the optimized loader uses C++11 thread and it does less error checks but may work most .obj data.
Here is some benchmark result. Time are measured on MacBook 12(Early 2016, Core m5 1.2GHz).
* Rungholt scene(6M triangles)
* old version(v0.9.x): 15500 msecs.
* baseline(v1.0.x): 6800 msecs(2.3x faster than old version)
* optimised: 1500 msecs(10x faster than old version, 4.5x faster than baseline)
## Tests
Unit tests are provided in `tests` directory. See `tests/README.md` for details.

View File

@@ -1,12 +1,22 @@
version: 0.9.{build} version: 1.0.{build}
# scripts that runs after repo cloning.
install:
- vcsetup.bat
platform: x64 platform: x64
configuration: Release
build: install:
parallel: true #######################################################################################
project: TinyObjLoaderSolution.sln # All external dependencies are installed in C:\projects\deps
#######################################################################################
- mkdir C:\projects\deps
#######################################################################################
# Install Ninja
#######################################################################################
- set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip"
- appveyor DownloadFile %NINJA_URL% -FileName ninja.zip
- 7z x ninja.zip -oC:\projects\deps\ninja > nul
- set PATH=C:\projects\deps\ninja;%PATH%
- ninja --version
build_script:
- cd tests
- vcbuild.bat

View File

@@ -1,16 +1,53 @@
# build.ninja ninja_required_version = 1.4
cc = clang
cxx = clang++
cflags = -Werror -Weverything
cxxflags = -Werror -Weverything
rule compile gnubuilddir = build
command = $cxx $cxxflags -c $in -o $out gnudefines =
gnuincludes = -I.
gnucflags = -O2 -g
gnucxxflags = -O2 -g -pedantic -Wall -Wextra -Wcast-align -Wcast-qual $
-Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self $
-Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast $
-Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion $
-Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror $
-Wno-unused -fsanitize=address
gnuldflags = -fsanitize=address
rule link pool link_pool
command = $cxx $in -o $out depth = 1
build test.o: compile test.cc rule gnucxx
build test: link test.o command = $gnucxx -MMD -MF $out.d $gnudefines $gnuincludes $gnucxxflags $
-c $in -o $out
description = CXX $out
depfile = $out.d
deps = gcc
rule gnucc
command = $gnucc -MMD -MF $out.d $gnudefines $gnuincludes $gnucflags -c $
$in -o $out
description = CC $out
depfile = $out.d
deps = gcc
rule gnulink
command = $gnuld -o $out $in $libs $gnuldflags
description = LINK $out
pool = link_pool
rule gnuar
command = $gnuar rsc $out $in
description = AR $out
pool = link_pool
rule gnustamp
command = touch $out
description = STAMP $out
default test gnucxx = g++
gnucc = gcc
gnuld = $gnucxx
gnuar = ar
build loader_example.o: gnucxx loader_example.cc
build loader_example: gnulink loader_example.o
build all: phony loader_example
default all

6323
deps/cpplint.py vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
all:
clang++ -I../../ -Wall -g -o example main.cc

View File

@@ -0,0 +1,171 @@
//
// An example of how to use callback API.
// This example is minimum and incomplete. Just showing the usage of callback
// API.
// You need to implement your own Mesh data struct constrution based on this
// example in practical.
//
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
typedef struct {
std::vector<float> vertices;
std::vector<float> normals;
std::vector<float> texcoords;
std::vector<int> v_indices;
std::vector<int> vn_indices;
std::vector<int> vt_indices;
std::vector<tinyobj::material_t> materials;
} MyMesh;
void vertex_cb(void *user_data, float x, float y, float z, float w) {
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
printf("v[%ld] = %f, %f, %f (w %f)\n", mesh->vertices.size() / 3, x, y, z, w);
mesh->vertices.push_back(x);
mesh->vertices.push_back(y);
mesh->vertices.push_back(z);
// Discard w
}
void normal_cb(void *user_data, float x, float y, float z) {
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
printf("vn[%ld] = %f, %f, %f\n", mesh->normals.size() / 3, x, y, z);
mesh->normals.push_back(x);
mesh->normals.push_back(y);
mesh->normals.push_back(z);
}
void texcoord_cb(void *user_data, float x, float y, float z) {
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
printf("vt[%ld] = %f, %f, %f\n", mesh->texcoords.size() / 3, x, y, z);
mesh->texcoords.push_back(x);
mesh->texcoords.push_back(y);
mesh->texcoords.push_back(z);
}
void index_cb(void *user_data, tinyobj::index_t *indices, int num_indices) {
// NOTE: the value of each index is raw value.
// For example, the application must manually adjust the index with offset
// (e.g. v_indices.size()) when the value is negative(whic means relative
// index).
// Also, the first index starts with 1, not 0.
// See fixIndex() function in tiny_obj_loader.h for details.
// Also, 0 is set for the index value which
// does not exist in .obj
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
for (int i = 0; i < num_indices; i++) {
tinyobj::index_t idx = indices[i];
printf("idx[%ld] = %d, %d, %d\n", mesh->v_indices.size(), idx.vertex_index,
idx.normal_index, idx.texcoord_index);
if (idx.vertex_index != 0) {
mesh->v_indices.push_back(idx.vertex_index);
}
if (idx.normal_index != 0) {
mesh->vn_indices.push_back(idx.normal_index);
}
if (idx.texcoord_index != 0) {
mesh->vt_indices.push_back(idx.texcoord_index);
}
}
}
void usemtl_cb(void *user_data, const char *name, int material_idx) {
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
if ((material_idx > -1) && (material_idx < mesh->materials.size())) {
printf("usemtl. material id = %d(name = %s)\n", material_idx,
mesh->materials[material_idx].name.c_str());
} else {
printf("usemtl. name = %s\n", name);
}
}
void mtllib_cb(void *user_data, const tinyobj::material_t *materials,
int num_materials) {
MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
printf("mtllib. # of materials = %d\n", num_materials);
for (int i = 0; i < num_materials; i++) {
mesh->materials.push_back(materials[i]);
}
}
void group_cb(void *user_data, const char **names, int num_names) {
// MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
printf("group : name = \n");
for (int i = 0; i < num_names; i++) {
printf(" %s\n", names[i]);
}
}
void object_cb(void *user_data, const char *name) {
// MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
printf("object : name = %s\n", name);
}
int main(int argc, char **argv) {
tinyobj::callback_t cb;
cb.vertex_cb = vertex_cb;
cb.normal_cb = normal_cb;
cb.texcoord_cb = texcoord_cb;
cb.index_cb = index_cb;
cb.usemtl_cb = usemtl_cb;
cb.mtllib_cb = mtllib_cb;
cb.group_cb = group_cb;
cb.object_cb = object_cb;
MyMesh mesh;
std::string warn;
std::string err;
std::string filename = "../../models/cornell_box.obj";
if (argc > 1) {
filename = std::string(argv[1]);
}
std::ifstream ifs(filename.c_str());
if (ifs.fail()) {
std::cerr << "file not found." << std::endl;
return EXIT_FAILURE;
}
tinyobj::MaterialFileReader mtlReader("../../models/");
bool ret = tinyobj::LoadObjWithCallback(ifs, cb, &mesh, &mtlReader, &warn, &err);
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
std::cerr << "Failed to parse .obj" << std::endl;
return EXIT_FAILURE;
}
printf("# of vertices = %ld\n", mesh.vertices.size() / 3);
printf("# of normals = %ld\n", mesh.normals.size() / 3);
printf("# of texcoords = %ld\n", mesh.texcoords.size() / 2);
printf("# of vertex indices = %ld\n", mesh.v_indices.size());
printf("# of normal indices = %ld\n", mesh.vn_indices.size());
printf("# of texcoord indices = %ld\n", mesh.vt_indices.size());
printf("# of materials = %ld\n", mesh.materials.size());
return EXIT_SUCCESS;
}

View File

@@ -1,9 +1,10 @@
// //
// Stiches multiple .obj files into one .obj. // Stiches multiple .obj files into one .obj.
// //
#include "../../tiny_obj_loader.h"
#include "obj_writer.h" #include "obj_writer.h"
#include "../../tiny_obj_loader.h"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
@@ -11,27 +12,59 @@
typedef std::vector<tinyobj::shape_t> Shape; typedef std::vector<tinyobj::shape_t> Shape;
typedef std::vector<tinyobj::material_t> Material; typedef std::vector<tinyobj::material_t> Material;
typedef tinyobj::attrib_t Attribute;
void void
StichObjs( StichObjs(
tinyobj::attrib_t& out_attribute,
std::vector<tinyobj::shape_t>& out_shape, std::vector<tinyobj::shape_t>& out_shape,
std::vector<tinyobj::material_t>& out_material, std::vector<tinyobj::material_t>& out_material,
const std::vector<Attribute>& attributes,
const std::vector<Shape>& shapes, const std::vector<Shape>& shapes,
const std::vector<Material>& materials) const std::vector<Material>& materials)
{ {
int numShapes = 0; // The amount of attributes, shape-vectors and material-vecotrs should be the same.
for (size_t i = 0; i < shapes.size(); i++) { if(attributes.size() != shapes.size() && attributes.size() != materials.size()){
numShapes += (int)shapes[i].size(); std::cerr << "Size of attributes, shapes and Materials don't fit!" << attributes.size() << " " << shapes.size() <<" " << materials.size() << std::endl;;
exit(1);
}
int num_shapes = 0;
// 4 values (vertices, normals, texcoords, colors)
std::vector<int> num_attributes(4, 0);
int num_materials = 0;
for(int i = 0; i < shapes.size(); i++){
num_shapes += shapes[i].size();
}
for(int i = 0; i < attributes.size(); i++){
num_attributes[0] += attributes[i].vertices.size();
num_attributes[1] += attributes[i].normals.size();
num_attributes[2] += attributes[i].texcoords.size();
num_attributes[3] += attributes[i].colors.size();
}
for(int i = 0; i < materials.size(); i++){
num_materials += materials[i].size();
} }
printf("Total # of shapes = %d\n", numShapes); // More performant, than push_back
int materialIdOffset = 0; out_attribute.vertices.resize(num_attributes[0]);
out_attribute.normals.resize(num_attributes[1]);
out_attribute.texcoords.resize(num_attributes[2]);
out_attribute.colors.resize(num_attributes[3]);
out_shape.resize(num_shapes);
out_material.resize(num_materials);
size_t face_offset = 0; int material_id_offset = 0;
int shape_id_offset = 0;
int vertex_idx_offset = 0;
int normal_idx_offset = 0;
int texcoord_idx_offset = 0;
int color_idx_offset = 0;
// shapes.size() = attributes.size() = materials.size()
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
// Copy shapes
for (size_t k = 0; k < shapes[i].size(); k++) { for (size_t k = 0; k < shapes[i].size(); k++) {
std::string new_name = shapes[i][k].name; std::string new_name = shapes[i][k].name;
// Add suffix // Add suffix
char buf[1024]; char buf[1024];
@@ -39,36 +72,51 @@ StichObjs(
new_name += std::string(buf); new_name += std::string(buf);
printf("shape[%ld][%ld].name = %s\n", i, k, shapes[i][k].name.c_str()); printf("shape[%ld][%ld].name = %s\n", i, k, shapes[i][k].name.c_str());
assert((shapes[i][k].mesh.indices.size() % 3) == 0);
assert((shapes[i][k].mesh.positions.size() % 3) == 0);
tinyobj::shape_t new_shape = shapes[i][k]; tinyobj::shape_t new_shape = shapes[i][k];
// Add offset. // Add material offset.
for (size_t f = 0; f < new_shape.mesh.material_ids.size(); f++) { for(size_t f = 0; f < new_shape.mesh.material_ids.size(); f++) {
new_shape.mesh.material_ids[f] += materialIdOffset; new_shape.mesh.material_ids[f] += material_id_offset;
}
// Add indices offset.
for(size_t f = 0; f < new_shape.mesh.indices.size(); f++){
tinyobj::index_t& ref = new_shape.mesh.indices[f];
if(ref.vertex_index > -1){
ref.vertex_index += vertex_idx_offset;
}
if(ref.normal_index > -1){
ref.normal_index += normal_idx_offset;
}
if(ref.texcoord_index > -1){
ref.texcoord_index += texcoord_idx_offset;
}
} }
new_shape.name = new_name; new_shape.name = new_name;
printf("shape[%ld][%ld].new_name = %s\n", i, k, new_shape.name.c_str()); printf("shape[%ld][%ld].new_name = %s\n", i, k, new_shape.name.c_str());
out_shape.push_back(new_shape); out_shape[shape_id_offset++] = new_shape;
} }
materialIdOffset += materials[i].size(); // Copy materials
}
for (size_t i = 0; i < materials.size(); i++) {
for (size_t k = 0; k < materials[i].size(); k++) { for (size_t k = 0; k < materials[i].size(); k++) {
out_material.push_back(materials[i][k]); out_material[material_id_offset++] = materials[i][k];
} }
}
// Copy attributes (3 floats per vertex, 3 floats per normal, 2 floats per texture-coordinate, 3 floats per color)
// You could also include a check here, if the sizes are dividable by 3 (resp. 2), but it's safe to simply assume, they do.
std::copy(attributes[i].vertices.begin(), attributes[i].vertices.end(), out_attribute.vertices.begin() + vertex_idx_offset * 3);
vertex_idx_offset += attributes[i].vertices.size() / 3;
std::copy(attributes[i].normals.begin(), attributes[i].normals.end(), out_attribute.normals.begin() + normal_idx_offset * 3);
normal_idx_offset += attributes[i].normals.size() / 3;
std::copy(attributes[i].texcoords.begin(), attributes[i].texcoords.end(), out_attribute.texcoords.begin() + texcoord_idx_offset * 2);
texcoord_idx_offset += attributes[i].texcoords.size() / 2;
std::copy(attributes[i].colors.begin(), attributes[i].colors.end(), out_attribute.colors.begin() + color_idx_offset);
color_idx_offset += attributes[i].colors.size();
}
} }
int int main(int argc, char **argv)
main(
int argc,
char **argv)
{ {
if (argc < 3) { if (argc < 3) {
printf("Usage: obj_sticher input0.obj input1.obj ... output.obj\n"); printf("Usage: obj_sticher input0.obj input1.obj ... output.obj\n");
@@ -78,16 +126,16 @@ main(
int num_objfiles = argc - 2; int num_objfiles = argc - 2;
std::string out_filename = std::string(argv[argc-1]); // last element std::string out_filename = std::string(argv[argc-1]); // last element
std::vector<Shape> shapes; std::vector<Attribute> attributes(num_objfiles);
std::vector<Material> materials; std::vector<Shape> shapes(num_objfiles);
shapes.resize(num_objfiles); std::vector<Material> materials(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;
std::string warn;
std::string err; std::string err;
bool ret = tinyobj::LoadObj(shapes[i], materials[i], err, argv[i+1]); bool ret = tinyobj::LoadObj(&attributes[i], &shapes[i], &materials[i], &warn, &err, argv[i+1]);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
@@ -98,12 +146,13 @@ main(
std::cout << "DONE." << std::endl; std::cout << "DONE." << std::endl;
} }
std::vector<tinyobj::shape_t> out_shape; Attribute out_attribute;
std::vector<tinyobj::material_t> out_material; Shape out_shape;
StichObjs(out_shape, out_material, shapes, materials); Material out_material;
StichObjs(out_attribute, out_shape, out_material, attributes, shapes, materials);
bool coordTransform = true; bool coordTransform = true;
bool ret = WriteObj(out_filename, out_shape, out_material, coordTransform); bool ret = WriteObj(out_filename, out_attribute, out_shape, out_material, coordTransform);
assert(ret); assert(ret);
return 0; return 0;

View File

@@ -30,6 +30,8 @@ bool WriteMat(const std::string& filename, const std::vector<tinyobj::material_t
fprintf(fp, "Ke %f %f %f\n", mat.emission[0], mat.emission[1], mat.emission[2]); fprintf(fp, "Ke %f %f %f\n", mat.emission[0], mat.emission[1], mat.emission[2]);
fprintf(fp, "Ns %f\n", mat.shininess); fprintf(fp, "Ns %f\n", mat.shininess);
fprintf(fp, "Ni %f\n", mat.ior); fprintf(fp, "Ni %f\n", mat.ior);
fprintf(fp, "illum %d\n", mat.illum);
fprintf(fp, "\n");
// @todo { texture } // @todo { texture }
} }
@@ -38,7 +40,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 coordTransform) { bool WriteObj(const std::string& filename, const tinyobj::attrib_t& attributes, 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());
@@ -48,17 +50,53 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
std::string basename = GetFileBasename(filename); std::string basename = GetFileBasename(filename);
std::string material_filename = basename + ".mtl"; std::string material_filename = basename + ".mtl";
int v_offset = 0;
int vn_offset = 0;
int vt_offset = 0;
int prev_material_id = -1; int prev_material_id = -1;
fprintf(fp, "mtllib %s\n", material_filename.c_str()); fprintf(fp, "mtllib %s\n\n", material_filename.c_str());
// facevarying vtx
for (size_t k = 0; k < attributes.vertices.size(); k+=3) {
if (coordTransform) {
fprintf(fp, "v %f %f %f\n",
attributes.vertices[k + 0],
attributes.vertices[k + 2],
-attributes.vertices[k + 1]);
} else {
fprintf(fp, "v %f %f %f\n",
attributes.vertices[k + 0],
attributes.vertices[k + 1],
attributes.vertices[k + 2]);
}
}
fprintf(fp, "\n");
// facevarying normal
for (size_t k = 0; k < attributes.normals.size(); k += 3) {
if (coordTransform) {
fprintf(fp, "vn %f %f %f\n",
attributes.normals[k + 0],
attributes.normals[k + 2],
-attributes.normals[k + 1]);
} else {
fprintf(fp, "vn %f %f %f\n",
attributes.normals[k + 0],
attributes.normals[k + 1],
attributes.normals[k + 2]);
}
}
fprintf(fp, "\n");
// facevarying texcoord
for (size_t k = 0; k < attributes.texcoords.size(); k += 2) {
fprintf(fp, "vt %f %f\n",
attributes.texcoords[k + 0],
attributes.texcoords[k + 1]);
}
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
fprintf(fp, "\n");
bool has_vn = false;
bool has_vt = false;
if (shapes[i].name.empty()) { if (shapes[i].name.empty()) {
fprintf(fp, "g Unknown\n"); fprintf(fp, "g Unknown\n");
@@ -66,101 +104,53 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
fprintf(fp, "g %s\n", shapes[i].name.c_str()); fprintf(fp, "g %s\n", shapes[i].name.c_str());
} }
//if (!shapes[i].material.name.empty()) { bool has_vn = false;
// fprintf(fp, "usemtl %s\n", shapes[i].material.name.c_str()); bool has_vt = false;
//} // Assumes normals and textures are set shape-wise.
if(shapes[i].mesh.indices.size() > 0){
// facevarying vtx has_vn = shapes[i].mesh.indices[0].normal_index != -1;
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { has_vt = shapes[i].mesh.indices[0].texcoord_index != -1;
for (int j = 0; j < 3; 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",
shapes[i].mesh.positions[3*idx+0],
shapes[i].mesh.positions[3*idx+1],
shapes[i].mesh.positions[3*idx+2]);
}
}
} }
// facevarying normal
if (shapes[i].mesh.normals.size() > 0) {
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
for (int j = 0; j < 3; 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",
shapes[i].mesh.normals[3*idx+0],
shapes[i].mesh.normals[3*idx+1],
shapes[i].mesh.normals[3*idx+2]);
}
}
}
}
if (shapes[i].mesh.normals.size() > 0) has_vn = true;
// facevarying texcoord
if (shapes[i].mesh.texcoords.size() > 0) {
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
for (int j = 0; j < 3; j++) {
int idx = shapes[i].mesh.indices[3*k+j];
fprintf(fp, "vt %f %f\n",
shapes[i].mesh.texcoords[2*idx+0],
shapes[i].mesh.texcoords[2*idx+1]);
}
}
}
if (shapes[i].mesh.texcoords.size() > 0) has_vt = true;
// face // face
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) { int face_index = 0;
for (size_t k = 0; k < shapes[i].mesh.indices.size(); k += shapes[i].mesh.num_face_vertices[face_index++]) {
// Face index is 1-base. // Check Materials
//int v0 = shapes[i].mesh.indices[3*k+0] + 1 + v_offset; int material_id = shapes[i].mesh.material_ids[face_index];
//int v1 = shapes[i].mesh.indices[3*k+1] + 1 + v_offset;
//int v2 = shapes[i].mesh.indices[3*k+2] + 1 + v_offset;
int v0 = (3*k + 0) + 1 + v_offset;
int v1 = (3*k + 1) + 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];
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;
fprintf(fp, "usemtl %s\n", material_name.c_str()); fprintf(fp, "usemtl %s\n", material_name.c_str());
prev_material_id = material_id; prev_material_id = material_id;
} }
if (has_vn && has_vt) { unsigned char v_per_f = shapes[i].mesh.num_face_vertices[face_index];
fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", // Imperformant, but if you want to have variable vertices per face, you need some kind of a dynamic loop.
v0, vt0, v0, v1, vt1, v1, v2, vt2, v2); fprintf(fp, "f");
} else if (has_vn && !has_vt) { for(int l = 0; l < v_per_f; l++){
fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2); const tinyobj::index_t& ref = shapes[i].mesh.indices[k + l];
} else if (!has_vn && has_vt) { if(has_vn && has_vt){
fprintf(fp, "f %d/%d %d/%d %d/%d\n", v0, v0, v1, v1, v2, v2); // v0/t0/vn0
} else { fprintf(fp, " %d/%d/%d", ref.vertex_index + 1, ref.texcoord_index + 1, ref.normal_index + 1);
fprintf(fp, "f %d %d %d\n", v0, v1, v2); continue;
}
if(has_vn && !has_vt){
// v0//vn0
fprintf(fp, " %d//%d", ref.vertex_index + 1, ref.normal_index + 1);
continue;
}
if(!has_vn && has_vt){
// v0/vt0
fprintf(fp, " %d/%d", ref.vertex_index + 1, ref.texcoord_index + 1);
continue;
}
if(!has_vn && !has_vt){
// v0 v1 v2
fprintf(fp, " %d", ref.vertex_index + 1);
continue;
}
} }
fprintf(fp, "\n");
} }
v_offset += shapes[i].mesh.indices.size();
//vn_offset += shapes[i].mesh.normals.size() / 3;
vt_offset += shapes[i].mesh.texcoords.size() / 2;
} }
fclose(fp); fclose(fp);
@@ -172,5 +162,3 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
return ret; return ret;
} }

View File

@@ -3,7 +3,6 @@
#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, bool coordTransform = false); extern bool WriteObj(const std::string& filename, const tinyobj::attrib_t& attributes, 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__

42
examples/viewer/README.md Normal file
View File

@@ -0,0 +1,42 @@
# Simple .obj viewer with glew + glfw3 + OpenGL
## Requirements
* premake5
* glfw3
* glew
## Build on MaCOSX
Install glfw3 and glew using brew.
Then,
$ premake5 gmake
$ make
## Build on Linux
Set `PKG_CONFIG_PATH` or Edit path to glfw3 and glew in `premake4.lua`
Then,
$ premake5 gmake
$ make
## Build on Windows.
* Visual Studio 2013
* Windows 64bit
* 32bit may work.
Put glfw3 and glew library somewhere and replace include and lib path in `premake4.lua`
Then,
> premake5.exe vs2013
## TODO
* [ ] Support per-face material.
* [ ] Use shader-based GL rendering.
* [ ] PBR shader support.

View File

@@ -0,0 +1,44 @@
solution "objview"
-- location ( "build" )
configurations { "Release", "Debug" }
platforms {"native", "x64", "x32"}
project "objview"
kind "ConsoleApp"
language "C++"
files { "viewer.cc", "trackball.cc" }
includedirs { "./" }
includedirs { "../../" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
linkoptions { "-pthread" }
configuration { "windows" }
-- Path to GLFW3
includedirs { '../../../../local/glfw-3.1.2.bin.WIN64/include' }
libdirs { '../../../../local/glfw-3.1.2.bin.WIN64/lib-vc2013' }
-- Path to GLEW
includedirs { '../../../../local/glew-1.13.0/include' }
libdirs { '../../../../local/glew-1.13.0/lib/Release/x64' }
links { "glfw3", "glew32", "gdi32", "winmm", "user32", "glu32","opengl32", "kernel32" }
defines { "_CRT_SECURE_NO_WARNINGS" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw3", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols", "ExtraWarnings"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize", "ExtraWarnings"}

6755
examples/viewer/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* Trackball code:
*
* Implementation of a virtual trackball.
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
*
* Vector manip code:
*
* Original code from:
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
*
* Much mucking with by:
* Gavin Bell
*/
#include <math.h>
#include "trackball.h"
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
#define TRACKBALLSIZE (0.8)
/*
* Local function prototypes (not defined in trackball.h)
*/
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float[4]);
static void vzero(float *v) {
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
}
static void vset(float *v, float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
static void vsub(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] - src2[0];
dst[1] = src1[1] - src2[1];
dst[2] = src1[2] - src2[2];
}
static void vcopy(const float *v1, float *v2) {
register int i;
for (i = 0; i < 3; i++)
v2[i] = v1[i];
}
static void vcross(const float *v1, const float *v2, float *cross) {
float temp[3];
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
vcopy(temp, cross);
}
static float vlength(const float *v) {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
static void vscale(float *v, float div) {
v[0] *= div;
v[1] *= div;
v[2] *= div;
}
static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); }
static float vdot(const float *v1, const float *v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
static void vadd(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] + src2[0];
dst[1] = src1[1] + src2[1];
dst[2] = src1[2] + src2[2];
}
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
float a[3]; /* Axis of rotation */
float phi; /* how much to rotate about axis */
float p1[3], p2[3], d[3];
float t;
if (p1x == p2x && p1y == p2y) {
/* Zero rotation */
vzero(q);
q[3] = 1.0;
return;
}
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
/*
* Now, we want the cross product of P1 and P2
*/
vcross(p2, p1, a);
/*
* Figure out how much to rotate around that axis.
*/
vsub(p1, p2, d);
t = vlength(d) / (2.0 * TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0)
t = 1.0;
if (t < -1.0)
t = -1.0;
phi = 2.0 * asin(t);
axis_to_quat(a, phi, q);
}
/*
* Given an axis and angle, compute quaternion.
*/
void axis_to_quat(float a[3], float phi, float q[4]) {
vnormal(a);
vcopy(a, q);
vscale(q, sin(phi / 2.0));
q[3] = cos(phi / 2.0);
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
static float tb_project_to_sphere(float r, float x, float y) {
float d, t, z;
d = sqrt(x * x + y * y);
if (d < r * 0.70710678118654752440) { /* Inside sphere */
z = sqrt(r * r - d * d);
} else { /* On hyperbola */
t = r / 1.41421356237309504880;
z = t * t / d;
}
return z;
}
/*
* Given two rotations, e1 and e2, expressed as quaternion rotations,
* figure out the equivalent single rotation and stuff it into dest.
*
* This routine also normalizes the result every RENORMCOUNT times it is
* called, to keep error from creeping in.
*
* NOTE: This routine is written so that q1 or q2 may be the same
* as dest (or each other).
*/
#define RENORMCOUNT 97
void add_quats(float q1[4], float q2[4], float dest[4]) {
static int count = 0;
float t1[4], t2[4], t3[4];
float tf[4];
vcopy(q1, t1);
vscale(t1, q2[3]);
vcopy(q2, t2);
vscale(t2, q1[3]);
vcross(q2, q1, t3);
vadd(t1, t2, tf);
vadd(t3, tf, tf);
tf[3] = q1[3] * q2[3] - vdot(q1, q2);
dest[0] = tf[0];
dest[1] = tf[1];
dest[2] = tf[2];
dest[3] = tf[3];
if (++count > RENORMCOUNT) {
count = 0;
normalize_quat(dest);
}
}
/*
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
* If they don't add up to 1.0, dividing by their magnitued will
* renormalize them.
*
* Note: See the following for more information on quaternions:
*
* - Shoemake, K., Animating rotation with quaternion curves, Computer
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
* graphics, The Visual Computer 5, 2-13, 1989.
*/
static void normalize_quat(float q[4]) {
int i;
float mag;
mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
for (i = 0; i < 4; i++)
q[i] /= mag;
}
/*
* Build a rotation matrix, given a quaternion rotation.
*
*/
void build_rotmatrix(float m[4][4], const float q[4]) {
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
m[0][3] = 0.0;
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
m[1][3] = 0.0;
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}

View File

@@ -0,0 +1,75 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* trackball.h
* A virtual trackball implementation
* Written by Gavin Bell for Silicon Graphics, November 1988.
*/
/*
* Pass the x and y coordinates of the last and current positions of
* the mouse, scaled so they are from (-1.0 ... 1.0).
*
* The resulting rotation is returned as a quaternion rotation in the
* first paramater.
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
void negate_quat(float *q, float *qn);
/*
* Given two quaternions, add them together to get a third quaternion.
* Adding quaternions to get a compound rotation is analagous to adding
* translations to get a compound translation. When incrementally
* adding rotations, the first argument here should be the new
* rotation, the second and third the total rotation (which will be
* over-written with the resulting new total rotation).
*/
void add_quats(float *q1, float *q2, float *dest);
/*
* A useful function, builds a rotation matrix in Matrix based on
* given quaternion.
*/
void build_rotmatrix(float m[4][4], const float q[4]);
/*
* This function computes a quaternion based on an axis (defined by
* the given vector) and an angle about which to rotate. The angle is
* expressed in radians. The result is put into the third argument.
*/
void axis_to_quat(float a[3], float phi, float q[4]);

881
examples/viewer/viewer.cc Normal file
View File

@@ -0,0 +1,881 @@
//
// Simple .obj viewer(vertex only)
//
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <vector>
#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GLFW/glfw3.h>
#define TINYOBJLOADER_IMPLEMENTATION
#include "../../tiny_obj_loader.h"
#include "trackball.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#ifdef _WIN32
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#include <mmsystem.h>
#ifdef __cplusplus
}
#endif
#pragma comment(lib, "winmm.lib")
#else
#if defined(__unix__) || defined(__APPLE__)
#include <sys/time.h>
#else
#include <ctime>
#endif
#endif
class timerutil {
public:
#ifdef _WIN32
typedef DWORD time_t;
timerutil() { ::timeBeginPeriod(1); }
~timerutil() { ::timeEndPeriod(1); }
void start() { t_[0] = ::timeGetTime(); }
void end() { t_[1] = ::timeGetTime(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / 1000); }
time_t msec() { return (time_t)((t_[1] - t_[0])); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000); }
time_t current() { return ::timeGetTime(); }
#else
#if defined(__unix__) || defined(__APPLE__)
typedef unsigned long int time_t;
void start() { gettimeofday(tv + 0, &tz); }
void end() { gettimeofday(tv + 1, &tz); }
time_t sec() { return (time_t)(tv[1].tv_sec - tv[0].tv_sec); }
time_t msec() {
return this->sec() * 1000 +
(time_t)((tv[1].tv_usec - tv[0].tv_usec) / 1000);
}
time_t usec() {
return this->sec() * 1000000 + (time_t)(tv[1].tv_usec - tv[0].tv_usec);
}
time_t current() {
struct timeval t;
gettimeofday(&t, NULL);
return (time_t)(t.tv_sec * 1000 + t.tv_usec);
}
#else // C timer
// using namespace std;
typedef clock_t time_t;
void start() { t_[0] = clock(); }
void end() { t_[1] = clock(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / CLOCKS_PER_SEC); }
time_t msec() { return (time_t)((t_[1] - t_[0]) * 1000 / CLOCKS_PER_SEC); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000000 / CLOCKS_PER_SEC); }
time_t current() { return (time_t)clock(); }
#endif
#endif
private:
#ifdef _WIN32
DWORD t_[2];
#else
#if defined(__unix__) || defined(__APPLE__)
struct timeval tv[2];
struct timezone tz;
#else
time_t t_[2];
#endif
#endif
};
typedef struct {
GLuint vb_id; // vertex buffer id
int numTriangles;
size_t material_id;
} DrawObject;
std::vector<DrawObject> gDrawObjects;
int width = 768;
int height = 768;
double prevMouseX, prevMouseY;
bool mouseLeftPressed;
bool mouseMiddlePressed;
bool mouseRightPressed;
float curr_quat[4];
float prev_quat[4];
float eye[3], lookat[3], up[3];
GLFWwindow* window;
static std::string GetBaseDir(const std::string& filepath) {
if (filepath.find_last_of("/\\") != std::string::npos)
return filepath.substr(0, filepath.find_last_of("/\\"));
return "";
}
static bool FileExists(const std::string& abs_filename) {
bool ret;
FILE* fp = fopen(abs_filename.c_str(), "rb");
if (fp) {
ret = true;
fclose(fp);
} else {
ret = false;
}
return ret;
}
static void CheckErrors(std::string desc) {
GLenum e = glGetError();
if (e != GL_NO_ERROR) {
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
exit(20);
}
}
static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
float v10[3];
v10[0] = v1[0] - v0[0];
v10[1] = v1[1] - v0[1];
v10[2] = v1[2] - v0[2];
float v20[3];
v20[0] = v2[0] - v0[0];
v20[1] = v2[1] - v0[1];
v20[2] = v2[2] - v0[2];
N[0] = v20[1] * v10[2] - v20[2] * v10[1];
N[1] = v20[2] * v10[0] - v20[0] * v10[2];
N[2] = v20[0] * v10[1] - v20[1] * v10[0];
float len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
N[0] /= len;
N[1] /= len;
N[2] /= len;
}
}
namespace // Local utility functions
{
struct vec3 {
float v[3];
vec3() {
v[0] = 0.0f;
v[1] = 0.0f;
v[2] = 0.0f;
}
};
void normalizeVector(vec3 &v) {
float len2 = v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
v.v[0] /= len;
v.v[1] /= len;
v.v[2] /= len;
}
}
// Check if `mesh_t` contains smoothing group id.
bool hasSmoothingGroup(const tinyobj::shape_t& shape)
{
for (size_t i = 0; i < shape.mesh.smoothing_group_ids.size(); i++) {
if (shape.mesh.smoothing_group_ids[i] > 0) {
return true;
}
}
return false;
}
void computeSmoothingNormals(const tinyobj::attrib_t& attrib, const tinyobj::shape_t& shape,
std::map<int, vec3>& smoothVertexNormals) {
smoothVertexNormals.clear();
std::map<int, vec3>::iterator iter;
for (size_t f = 0; f < shape.mesh.indices.size() / 3; f++) {
// Get the three indexes of the face (all faces are triangular)
tinyobj::index_t idx0 = shape.mesh.indices[3 * f + 0];
tinyobj::index_t idx1 = shape.mesh.indices[3 * f + 1];
tinyobj::index_t idx2 = shape.mesh.indices[3 * f + 2];
// Get the three vertex indexes and coordinates
int vi[3]; // indexes
float v[3][3]; // coordinates
for (int k = 0; k < 3; k++) {
vi[0] = idx0.vertex_index;
vi[1] = idx1.vertex_index;
vi[2] = idx2.vertex_index;
assert(vi[0] >= 0);
assert(vi[1] >= 0);
assert(vi[2] >= 0);
v[0][k] = attrib.vertices[3 * vi[0] + k];
v[1][k] = attrib.vertices[3 * vi[1] + k];
v[2][k] = attrib.vertices[3 * vi[2] + k];
}
// Compute the normal of the face
float normal[3];
CalcNormal(normal, v[0], v[1], v[2]);
// Add the normal to the three vertexes
for (size_t i = 0; i < 3; ++i) {
iter = smoothVertexNormals.find(vi[i]);
if (iter != smoothVertexNormals.end()) {
// add
iter->second.v[0] += normal[0];
iter->second.v[1] += normal[1];
iter->second.v[2] += normal[2];
} else {
smoothVertexNormals[vi[i]].v[0] = normal[0];
smoothVertexNormals[vi[i]].v[1] = normal[1];
smoothVertexNormals[vi[i]].v[2] = normal[2];
}
}
} // f
// Normalize the normals, that is, make them unit vectors
for (iter = smoothVertexNormals.begin(); iter != smoothVertexNormals.end();
iter++) {
normalizeVector(iter->second);
}
} // computeSmoothingNormals
} // namespace
static bool LoadObjAndConvert(float bmin[3], float bmax[3],
std::vector<DrawObject>* drawObjects,
std::vector<tinyobj::material_t>& materials,
std::map<std::string, GLuint>& textures,
const char* filename) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
timerutil tm;
tm.start();
std::string base_dir = GetBaseDir(filename);
if (base_dir.empty()) {
base_dir = ".";
}
#ifdef _WIN32
base_dir += "\\";
#else
base_dir += "/";
#endif
std::string warn;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename,
base_dir.c_str());
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}
if (!err.empty()) {
std::cerr << err << std::endl;
}
tm.end();
if (!ret) {
std::cerr << "Failed to load " << filename << std::endl;
return false;
}
printf("Parsing time: %d [ms]\n", (int)tm.msec());
printf("# of vertices = %d\n", (int)(attrib.vertices.size()) / 3);
printf("# of normals = %d\n", (int)(attrib.normals.size()) / 3);
printf("# of texcoords = %d\n", (int)(attrib.texcoords.size()) / 2);
printf("# of materials = %d\n", (int)materials.size());
printf("# of shapes = %d\n", (int)shapes.size());
// Append `default` material
materials.push_back(tinyobj::material_t());
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%d].diffuse_texname = %s\n", int(i),
materials[i].diffuse_texname.c_str());
}
// Load diffuse textures
{
for (size_t m = 0; m < materials.size(); m++) {
tinyobj::material_t* mp = &materials[m];
if (mp->diffuse_texname.length() > 0) {
// Only load the texture if it is not already loaded
if (textures.find(mp->diffuse_texname) == textures.end()) {
GLuint texture_id;
int w, h;
int comp;
std::string texture_filename = mp->diffuse_texname;
if (!FileExists(texture_filename)) {
// Append base dir.
texture_filename = base_dir + mp->diffuse_texname;
if (!FileExists(texture_filename)) {
std::cerr << "Unable to find file: " << mp->diffuse_texname
<< std::endl;
exit(1);
}
}
unsigned char* image =
stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
if (!image) {
std::cerr << "Unable to load texture: " << texture_filename
<< std::endl;
exit(1);
}
std::cout << "Loaded texture: " << texture_filename << ", w = " << w
<< ", h = " << h << ", comp = " << comp << std::endl;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (comp == 3) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
GL_UNSIGNED_BYTE, image);
} else if (comp == 4) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, image);
} else {
assert(0); // TODO
}
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
}
}
}
}
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
{
for (size_t s = 0; s < shapes.size(); s++) {
DrawObject o;
std::vector<float> buffer; // pos(3float), normal(3float), color(3float)
// Check for smoothing group and compute smoothing normals
std::map<int, vec3> smoothVertexNormals;
if (hasSmoothingGroup(shapes[s]) > 0) {
std::cout << "Compute smoothingNormal for shape [" << s << "]" << std::endl;
computeSmoothingNormals(attrib, shapes[s], smoothVertexNormals);
}
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];
int current_material_id = shapes[s].mesh.material_ids[f];
if ((current_material_id < 0) ||
(current_material_id >= static_cast<int>(materials.size()))) {
// Invaid material ID. Use default material.
current_material_id =
materials.size() -
1; // Default material is added to the last item in `materials`.
}
// if (current_material_id >= materials.size()) {
// std::cerr << "Invalid material index: " << current_material_id <<
// std::endl;
//}
//
float diffuse[3];
for (size_t i = 0; i < 3; i++) {
diffuse[i] = materials[current_material_id].diffuse[i];
}
float tc[3][2];
if (attrib.texcoords.size() > 0) {
if ((idx0.texcoord_index < 0) || (idx1.texcoord_index < 0) ||
(idx2.texcoord_index < 0)) {
// face does not contain valid uv index.
tc[0][0] = 0.0f;
tc[0][1] = 0.0f;
tc[1][0] = 0.0f;
tc[1][1] = 0.0f;
tc[2][0] = 0.0f;
tc[2][1] = 0.0f;
} else {
assert(attrib.texcoords.size() >
size_t(2 * idx0.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx1.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx2.texcoord_index + 1));
// Flip Y coord.
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
}
} else {
tc[0][0] = 0.0f;
tc[0][1] = 0.0f;
tc[1][0] = 0.0f;
tc[1][1] = 0.0f;
tc[2][0] = 0.0f;
tc[2][1] = 0.0f;
}
float v[3][3];
for (int k = 0; k < 3; k++) {
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
assert(f0 >= 0);
assert(f1 >= 0);
assert(f2 >= 0);
v[0][k] = attrib.vertices[3 * f0 + k];
v[1][k] = attrib.vertices[3 * f1 + k];
v[2][k] = attrib.vertices[3 * f2 + k];
bmin[k] = std::min(v[0][k], bmin[k]);
bmin[k] = std::min(v[1][k], bmin[k]);
bmin[k] = std::min(v[2][k], bmin[k]);
bmax[k] = std::max(v[0][k], bmax[k]);
bmax[k] = std::max(v[1][k], bmax[k]);
bmax[k] = std::max(v[2][k], bmax[k]);
}
float n[3][3];
{
bool invalid_normal_index = false;
if (attrib.normals.size() > 0) {
int nf0 = idx0.normal_index;
int nf1 = idx1.normal_index;
int nf2 = idx2.normal_index;
if ((nf0 < 0) || (nf1 < 0) || (nf2 < 0)) {
// normal index is missing from this face.
invalid_normal_index = true;
} else {
for (int k = 0; k < 3; k++) {
assert(size_t(3 * nf0 + k) < attrib.normals.size());
assert(size_t(3 * nf1 + k) < attrib.normals.size());
assert(size_t(3 * nf2 + k) < attrib.normals.size());
n[0][k] = attrib.normals[3 * nf0 + k];
n[1][k] = attrib.normals[3 * nf1 + k];
n[2][k] = attrib.normals[3 * nf2 + k];
}
}
} else {
invalid_normal_index = true;
}
if (invalid_normal_index && !smoothVertexNormals.empty()) {
// Use smoothing normals
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
if (f0 >= 0 && f1 >= 0 && f2 >= 0) {
n[0][0] = smoothVertexNormals[f0].v[0];
n[0][1] = smoothVertexNormals[f0].v[1];
n[0][2] = smoothVertexNormals[f0].v[2];
n[1][0] = smoothVertexNormals[f1].v[0];
n[1][1] = smoothVertexNormals[f1].v[1];
n[1][2] = smoothVertexNormals[f1].v[2];
n[2][0] = smoothVertexNormals[f2].v[0];
n[2][1] = smoothVertexNormals[f2].v[1];
n[2][2] = smoothVertexNormals[f2].v[2];
invalid_normal_index = false;
}
}
if (invalid_normal_index) {
// compute geometric normal
CalcNormal(n[0], v[0], v[1], v[2]);
n[1][0] = n[0][0];
n[1][1] = n[0][1];
n[1][2] = n[0][2];
n[2][0] = n[0][0];
n[2][1] = n[0][1];
n[2][2] = n[0][2];
}
}
for (int k = 0; k < 3; k++) {
buffer.push_back(v[k][0]);
buffer.push_back(v[k][1]);
buffer.push_back(v[k][2]);
buffer.push_back(n[k][0]);
buffer.push_back(n[k][1]);
buffer.push_back(n[k][2]);
// Combine normal and diffuse to get color.
float normal_factor = 0.2;
float diffuse_factor = 1 - normal_factor;
float c[3] = {n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
n[k][2] * normal_factor + diffuse[2] * diffuse_factor};
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
c[0] /= len;
c[1] /= len;
c[2] /= len;
}
buffer.push_back(c[0] * 0.5 + 0.5);
buffer.push_back(c[1] * 0.5 + 0.5);
buffer.push_back(c[2] * 0.5 + 0.5);
buffer.push_back(tc[k][0]);
buffer.push_back(tc[k][1]);
}
}
o.vb_id = 0;
o.numTriangles = 0;
// OpenGL viewer does not support texturing with per-face material.
if (shapes[s].mesh.material_ids.size() > 0 &&
shapes[s].mesh.material_ids.size() > s) {
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID
// of the first face.
} else {
o.material_id = materials.size() - 1; // = ID for default material.
}
printf("shape[%d] material_id %d\n", int(s), int(o.material_id));
if (buffer.size() > 0) {
glGenBuffers(1, &o.vb_id);
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float),
&buffer.at(0), GL_STATIC_DRAW);
o.numTriangles = buffer.size() / (3 + 3 + 3 + 2) /
3; // 3:vtx, 3:normal, 3:col, 2:texcoord
printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
o.numTriangles);
}
drawObjects->push_back(o);
}
}
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
return true;
}
static void reshapeFunc(GLFWwindow* window, int w, int h) {
int fb_w, fb_h;
// Get actual framebuffer size.
glfwGetFramebufferSize(window, &fb_w, &fb_h);
glViewport(0, 0, fb_w, fb_h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)w / (float)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
width = w;
height = h;
}
static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action,
int mods) {
(void)window;
(void)scancode;
(void)mods;
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
// Move camera
float mv_x = 0, mv_y = 0, mv_z = 0;
if (key == GLFW_KEY_K)
mv_x += 1;
else if (key == GLFW_KEY_J)
mv_x += -1;
else if (key == GLFW_KEY_L)
mv_y += 1;
else if (key == GLFW_KEY_H)
mv_y += -1;
else if (key == GLFW_KEY_P)
mv_z += 1;
else if (key == GLFW_KEY_N)
mv_z += -1;
// camera.move(mv_x * 0.05, mv_y * 0.05, mv_z * 0.05);
// Close window
if (key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE)
glfwSetWindowShouldClose(window, GL_TRUE);
// init_frame = true;
}
}
static void clickFunc(GLFWwindow* window, int button, int action, int mods) {
(void)window;
(void)mods;
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
mouseLeftPressed = true;
trackball(prev_quat, 0.0, 0.0, 0.0, 0.0);
} else if (action == GLFW_RELEASE) {
mouseLeftPressed = false;
}
}
if (button == GLFW_MOUSE_BUTTON_RIGHT) {
if (action == GLFW_PRESS) {
mouseRightPressed = true;
} else if (action == GLFW_RELEASE) {
mouseRightPressed = false;
}
}
if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
if (action == GLFW_PRESS) {
mouseMiddlePressed = true;
} else if (action == GLFW_RELEASE) {
mouseMiddlePressed = false;
}
}
}
static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
(void)window;
float rotScale = 1.0f;
float transScale = 2.0f;
if (mouseLeftPressed) {
trackball(prev_quat, rotScale * (2.0f * prevMouseX - width) / (float)width,
rotScale * (height - 2.0f * prevMouseY) / (float)height,
rotScale * (2.0f * mouse_x - width) / (float)width,
rotScale * (height - 2.0f * mouse_y) / (float)height);
add_quats(prev_quat, curr_quat, curr_quat);
} else if (mouseMiddlePressed) {
eye[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
lookat[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
eye[1] += transScale * (mouse_y - prevMouseY) / (float)height;
lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height;
} else if (mouseRightPressed) {
eye[2] += transScale * (mouse_y - prevMouseY) / (float)height;
lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height;
}
// Update mouse point
prevMouseX = mouse_x;
prevMouseY = mouse_y;
}
static void Draw(const std::vector<DrawObject>& drawObjects,
std::vector<tinyobj::material_t>& materials,
std::map<std::string, GLuint>& textures) {
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
GLsizei stride = (3 + 3 + 3 + 2) * sizeof(float);
for (size_t i = 0; i < drawObjects.size(); i++) {
DrawObject o = drawObjects[i];
if (o.vb_id < 1) {
continue;
}
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, 0);
if ((o.material_id < materials.size())) {
std::string diffuse_texname = materials[o.material_id].diffuse_texname;
if (textures.find(diffuse_texname) != textures.end()) {
glBindTexture(GL_TEXTURE_2D, textures[diffuse_texname]);
}
}
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
CheckErrors("drawarrays");
glBindTexture(GL_TEXTURE_2D, 0);
}
// draw wireframe
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
glColor3f(0.0f, 0.0f, 0.4f);
for (size_t i = 0; i < drawObjects.size(); i++) {
DrawObject o = drawObjects[i];
if (o.vb_id < 1) {
continue;
}
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, stride, (const void*)0);
glNormalPointer(GL_FLOAT, stride, (const void*)(sizeof(float) * 3));
glColorPointer(3, GL_FLOAT, stride, (const void*)(sizeof(float) * 6));
glTexCoordPointer(2, GL_FLOAT, stride, (const void*)(sizeof(float) * 9));
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
CheckErrors("drawarrays");
}
}
static void Init() {
trackball(curr_quat, 0, 0, 0, 0);
eye[0] = 0.0f;
eye[1] = 0.0f;
eye[2] = 3.0f;
lookat[0] = 0.0f;
lookat[1] = 0.0f;
lookat[2] = 0.0f;
up[0] = 0.0f;
up[1] = 1.0f;
up[2] = 0.0f;
}
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Needs input.obj\n" << std::endl;
return 0;
}
Init();
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW." << std::endl;
return -1;
}
window = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
if (window == NULL) {
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Callback
glfwSetWindowSizeCallback(window, reshapeFunc);
glfwSetKeyCallback(window, keyboardFunc);
glfwSetMouseButtonCallback(window, clickFunc);
glfwSetCursorPosCallback(window, motionFunc);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW." << std::endl;
return -1;
}
reshapeFunc(window, width, height);
float bmin[3], bmax[3];
std::vector<tinyobj::material_t> materials;
std::map<std::string, GLuint> textures;
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures,
argv[1])) {
return -1;
}
float maxExtent = 0.5f * (bmax[0] - bmin[0]);
if (maxExtent < 0.5f * (bmax[1] - bmin[1])) {
maxExtent = 0.5f * (bmax[1] - bmin[1]);
}
if (maxExtent < 0.5f * (bmax[2] - bmin[2])) {
maxExtent = 0.5f * (bmax[2] - bmin[2]);
}
while (glfwWindowShouldClose(window) == GL_FALSE) {
glfwPollEvents();
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// camera & rotate
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat mat[4][4];
gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0],
up[1], up[2]);
build_rotmatrix(mat, curr_quat);
glMultMatrixf(&mat[0][0]);
// Fit to -1, 1
glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent);
// Centerize object.
glTranslatef(-0.5 * (bmax[0] + bmin[0]), -0.5 * (bmax[1] + bmin[1]),
-0.5 * (bmax[2] + bmin[2]));
Draw(gDrawObjects, materials, textures);
glfwSwapBuffers(window);
}
glfwTerminate();
}

View File

@@ -0,0 +1,2 @@
all:
g++ -o voxelizer main.cc

View File

@@ -0,0 +1,5 @@
# Voxelize .obj and export it as also in .obj
## Third party library
This example uses https://github.com/karimnaaji/voxelizer, which is licensed under MIT Liense.

75
examples/voxelize/main.cc Normal file
View File

@@ -0,0 +1,75 @@
#define VOXELIZER_IMPLEMENTATION
#include "voxelizer.h"
#define TINYOBJLOADER_IMPLEMENTATION
#include "../../tiny_obj_loader.h"
bool Voxelize(const char* filename, float voxelsizex, float voxelsizey, float voxelsizez, float precision)
{
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename);
if (!err.empty()) {
printf("err: %s\n", err.c_str());
}
if (!ret) {
printf("failed to load : %s\n", filename);
return false;
}
if (shapes.size() == 0) {
printf("err: # of shapes are zero.\n");
return false;
}
// Only use first shape.
{
vx_mesh_t* mesh;
vx_mesh_t* result;
mesh = vx_mesh_alloc(attrib.vertices.size(), shapes[0].mesh.indices.size());
for (size_t f = 0; f < shapes[0].mesh.indices.size(); f++) {
mesh->indices[f] = shapes[0].mesh.indices[f].vertex_index;
}
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
mesh->vertices[v].x = attrib.vertices[3*v+0];
mesh->vertices[v].y = attrib.vertices[3*v+1];
mesh->vertices[v].z = attrib.vertices[3*v+2];
}
result = vx_voxelize(mesh, voxelsizex, voxelsizey, voxelsizez, precision);
printf("Number of vertices: %ld\n", result->nvertices);
printf("Number of indices: %ld\n", result->nindices);
}
return true;
}
int
main(
int argc,
char** argv)
{
if (argc < 4) {
printf("Usage: voxelize input.obj voxelsizex voxelsizey voxelsizez precision\n");
exit(-1);
}
const char* filename = argv[1];
float voxelsizex = atof(argv[2]);
float voxelsizey = atof(argv[3]);
float voxelsizez = atof(argv[4]);
float prec = atof(argv[5]);
bool ret = Voxelize(filename, voxelsizex, voxelsizey, voxelsizez, prec);
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -0,0 +1,764 @@
//
// LICENCE:
// The MIT License (MIT)
//
// Copyright (c) 2016 Karim Naaji, karim.naaji@gmail.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE
//
// REFERENCES:
// http://matthias-mueller-fischer.ch/publications/tetraederCollision.pdf
// http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/tribox2.txt
//
// HOWTO:
// #define VOXELIZER_IMPLEMENTATION
// #define VOXELIZER_DEBUG // Only if assertions need to be checked
// #include "voxelizer.h"
//
// HISTORY:
// - version 0.9.0: Initial
//
// TODO:
// - Triangle face merging
// - Add colors from input mesh
// - Potential issue with voxel bigger than triangle
//
#ifndef VOXELIZER_H
#define VOXELIZER_H
// ------------------------------------------------------------------------------------------------
// VOXELIZER PUBLIC API
//
#ifndef VOXELIZER_HELPERS
#include <stdlib.h> // malloc, calloc, free
#endif
typedef struct vx_vertex {
union {
float v[3];
struct {
float x;
float y;
float z;
};
};
} vx_vertex_t;
typedef struct vx_mesh {
vx_vertex_t* vertices; // Contiguous mesh vertices
vx_vertex_t* normals; // Contiguous mesh normals
unsigned int* indices; // Mesh indices
unsigned int* normalindices; // Mesh normal indices
size_t nindices; // The number of normal indices
size_t nvertices; // The number of vertices
size_t nnormals; // The number of normals
} vx_mesh_t;
vx_mesh_t* vx_voxelize(vx_mesh_t* _mesh, // The input mesh
float voxelsizex, // Voxel size on X-axis
float voxelsizey, // Voxel size on Y-axis
float voxelsizez, // Voxel size on Z-axis
float precision); // A precision factor that reduces "holes" artifact
// usually a precision = voxelsize / 10. works ok.
void vx_mesh_free(vx_mesh_t* _mesh);
vx_mesh_t* vx_mesh_alloc(int nindices, int nvertices);
// Voxelizer Helpers, define your own if needed
#ifndef VOXELIZER_HELPERS
#define VOXELIZER_HELPERS 1
#define VX_MIN(a, b) (a > b ? b : a)
#define VX_MAX(a, b) (a > b ? a : b)
#define VX_FINDMINMAX(x0, x1, x2, min, max) \
min = max = x0; \
if (x1 < min) min = x1; \
if (x1 > max) max = x1; \
if (x2 < min) min = x2; \
if (x2 > max) max = x2;
#define VX_CLAMP(v, lo, hi) VX_MAX(lo, VX_MIN(hi, v))
#define VX_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
#define VX_FREE(T) free(T)
#define VX_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
#define VX_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
#ifdef VOXELIZER_DEBUG
#define VX_ASSERT(STMT) if (!(STMT)) { *(int *)0 = 0; }
#else
#define VX_ASSERT(STMT)
#endif // VOXELIZER_DEBUG
#endif // VOXELIZER_HELPERS
//
// END VOXELIZER PUBLIC API
// ------------------------------------------------------------------------------------------------
#endif // VOXELIZER_H
#ifdef VOXELIZER_IMPLEMENTATION
#include <math.h> // ceil, fabs & al.
#include <stdbool.h> // hughh
#include <string.h> // memcpy
#define VOXELIZER_EPSILON (0.0000001)
#define VOXELIZER_NORMAL_INDICES_SIZE (6)
#define VOXELIZER_INDICES_SIZE (36)
#define VOXELIZER_HASH_TABLE_SIZE (4096)
unsigned int vx_voxel_indices[VOXELIZER_INDICES_SIZE] = {
0, 1, 2,
0, 2, 3,
3, 2, 6,
3, 6, 7,
0, 7, 4,
0, 3, 7,
4, 7, 5,
7, 6, 5,
0, 4, 5,
0, 5, 1,
1, 5, 6,
1, 6, 2,
};
float vx_normals[18] = {
0.0, -1.0, 0.0,
0.0, 1.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
-1.0, 0.0, 0.0,
0.0, 0.0, -1.0,
};
unsigned int vx_normal_indices[VOXELIZER_NORMAL_INDICES_SIZE] = {
3, 2, 1, 5, 4, 0,
};
typedef struct vx_aabb {
vx_vertex_t min;
vx_vertex_t max;
} vx_aabb_t;
typedef struct vx_edge {
vx_vertex_t p1;
vx_vertex_t p2;
} vx_edge_t;
typedef struct vx_triangle {
vx_vertex_t p1;
vx_vertex_t p2;
vx_vertex_t p3;
} vx_triangle_t;
typedef struct vx_hash_table_node {
struct vx_hash_table_node* next;
struct vx_hash_table_node* prev;
void* data;
} vx_hash_table_node_t;
typedef struct vx_hash_table {
vx_hash_table_node_t** elements;
size_t size;
} vx_hash_table_t;
vx_hash_table_t* vx__hash_table_alloc(size_t size)
{
vx_hash_table_t* table = VX_MALLOC(vx_hash_table_t, 1);
if (!table) { return NULL; }
table->size = size;
table->elements = VX_MALLOC(vx_hash_table_node_t*, size);
if (!table->elements) { return NULL; }
for (size_t i = 0; i < table->size; ++i) {
table->elements[i] = NULL;
}
return table;
}
void vx__hash_table_free(vx_hash_table_t* table, bool freedata)
{
for (size_t i = 0; i < table->size; ++i) {
vx_hash_table_node_t* node = table->elements[i];
if (node) {
if (node->next) {
while (node->next) {
node = node->next;
if (freedata) {
VX_FREE(node->prev->data);
}
VX_FREE(node->prev);
}
VX_FREE(node);
} else {
VX_FREE(node->data);
VX_FREE(node);
}
}
}
VX_FREE(table->elements);
VX_FREE(table);
}
bool vx__hash_table_insert(vx_hash_table_t* table,
size_t hash,
void* data,
bool (*compfunc)(void* d1, void* d2))
{
if (!table->elements[hash]) {
table->elements[hash] = VX_MALLOC(vx_hash_table_node_t, 1);
table->elements[hash]->prev = NULL;
table->elements[hash]->next = NULL;
table->elements[hash]->data = data;
} else {
vx_hash_table_node_t* node = table->elements[hash];
if (compfunc && compfunc(node->data, data)) {
return false;
}
while (node->next) {
node = node->next;
if (compfunc && compfunc(node->data, data)) {
return false;
}
}
vx_hash_table_node_t* nnode = VX_MALLOC(vx_hash_table_node_t, 1);
nnode->prev = node;
nnode->next = NULL;
nnode->data = data;
node->next = nnode;
}
return true;
}
void vx_mesh_free(vx_mesh_t* m)
{
VX_FREE(m->vertices);
m->vertices = NULL;
m->nvertices = 0;
VX_FREE(m->indices);
m->indices = NULL;
m->nindices = 0;
if (m->normals) { VX_FREE(m->normals); }
VX_FREE(m);
}
vx_mesh_t* vx_mesh_alloc(int nvertices, int nindices)
{
vx_mesh_t* m = VX_MALLOC(vx_mesh_t, 1);
if (!m) { return NULL; }
m->indices = VX_CALLOC(unsigned int, nindices);
if (!m->indices) { return NULL; }
m->vertices = VX_CALLOC(vx_vertex_t, nvertices);
if (!m->vertices) { return NULL; }
m->normals = NULL;
m->nindices = nindices;
m->nvertices = nvertices;
return m;
}
float vx__map_to_voxel(float position, float voxelSize, bool min)
{
float vox = (position + (position < 0.f ? -1.f : 1.f) * voxelSize * 0.5f) / voxelSize;
return (min ? floor(vox) : ceil(vox)) * voxelSize;
}
vx_vertex_t vx__vertex_cross(vx_vertex_t* v1, vx_vertex_t* v2)
{
vx_vertex_t cross;
cross.x = v1->y * v2->z - v1->z * v2->y;
cross.y = v1->z * v2->x - v1->x * v2->z;
cross.z = v1->x * v2->y - v1->y * v2->x;
return cross;
}
bool vx__vertex_equals(vx_vertex_t* v1, vx_vertex_t* v2) {
return fabs(v1->x - v2->x) < VOXELIZER_EPSILON &&
fabs(v1->y - v2->y) < VOXELIZER_EPSILON &&
fabs(v1->z - v2->z) < VOXELIZER_EPSILON;
}
bool vx__vertex_comp_func(void* a, void* b)
{
return vx__vertex_equals((vx_vertex_t*) a, (vx_vertex_t*) b);
}
void vx__vertex_sub(vx_vertex_t* a, vx_vertex_t* b)
{
a->x -= b->x;
a->y -= b->y;
a->z -= b->z;
}
void vx__vertex_add(vx_vertex_t* a, vx_vertex_t* b)
{
a->x += b->x;
a->y += b->y;
a->z += b->z;
}
void vx__vertex_multiply(vx_vertex_t* a, float v)
{
a->x *= v;
a->y *= v;
a->z *= v;
}
float vx__vertex_dot(vx_vertex_t* v1, vx_vertex_t* v2)
{
return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
}
int vx__plane_box_overlap(vx_vertex_t* normal,
float d,
vx_vertex_t* halfboxsize)
{
vx_vertex_t vmin, vmax;
for (int dim = 0; dim <= 2; dim++) {
if (normal->v[dim] > 0.0f) {
vmin.v[dim] = -halfboxsize->v[dim];
vmax.v[dim] = halfboxsize->v[dim];
} else {
vmin.v[dim] = halfboxsize->v[dim];
vmax.v[dim] = -halfboxsize->v[dim];
}
}
if (vx__vertex_dot(normal, &vmin) + d > 0.0f) {
return false;
}
if (vx__vertex_dot(normal, &vmax) + d >= 0.0f) {
return true;
}
return false;
}
#define AXISTEST_X01(a, b, fa, fb) \
p1 = a * v1.y - b * v1.z; \
p3 = a * v3.y - b * v3.z; \
if (p1 < p3) { \
min = p1; max = p3; \
} else { \
min = p3; max = p1; \
} \
rad = fa * halfboxsize.y + fb * halfboxsize.z; \
if (min > rad || max < -rad) { \
return false; \
} \
#define AXISTEST_X2(a, b, fa, fb) \
p1 = a * v1.y - b * v1.z; \
p2 = a * v2.y - b * v2.z; \
if (p1 < p2) { \
min = p1; max = p2; \
} else { \
min = p2; max = p1; \
} \
rad = fa * halfboxsize.y + fb * halfboxsize.z; \
if (min > rad || max < -rad) { \
return false; \
} \
#define AXISTEST_Y02(a, b, fa, fb) \
p1 = -a * v1.x + b * v1.z; \
p3 = -a * v3.x + b * v3.z; \
if (p1 < p3) { \
min = p1; max = p3; \
} else { \
min = p3; max = p1; \
} \
rad = fa * halfboxsize.x + fb * halfboxsize.z; \
if (min > rad || max < -rad) { \
return false; \
} \
#define AXISTEST_Y1(a, b, fa, fb) \
p1 = -a * v1.x + b * v1.z; \
p2 = -a * v2.x + b * v2.z; \
if (p1 < p2) { \
min = p1; max = p2; \
} else { \
min = p2; max = p1; \
} \
rad = fa * halfboxsize.x + fb * halfboxsize.z; \
if (min > rad || max < -rad) { \
return false; \
}
#define AXISTEST_Z12(a, b, fa, fb) \
p2 = a * v2.x - b * v2.y; \
p3 = a * v3.x - b * v3.y; \
if (p3 < p2) { \
min = p3; max = p2; \
} else { \
min = p2; max = p3; \
} \
rad = fa * halfboxsize.x + fb * halfboxsize.y; \
if (min > rad || max < -rad) { \
return false; \
}
#define AXISTEST_Z0(a, b, fa, fb) \
p1 = a * v1.x - b * v1.y; \
p2 = a * v2.x - b * v2.y; \
if (p1 < p2) { \
min = p1; max = p2; \
} else { \
min = p2; max = p1; \
} \
rad = fa * halfboxsize.x + fb * halfboxsize.y; \
if (min > rad || max < -rad) { \
return false; \
}
int vx__triangle_box_overlap(vx_vertex_t boxcenter,
vx_vertex_t halfboxsize,
vx_triangle_t triangle)
{
vx_vertex_t v1, v2, v3, normal, e1, e2, e3;
float min, max, d, p1, p2, p3, rad, fex, fey, fez;
v1 = triangle.p1;
v2 = triangle.p2;
v3 = triangle.p3;
vx__vertex_sub(&v1, &boxcenter);
vx__vertex_sub(&v2, &boxcenter);
vx__vertex_sub(&v3, &boxcenter);
e1 = v2;
e2 = v3;
e3 = v1;
vx__vertex_sub(&e1, &v1);
vx__vertex_sub(&e2, &v2);
vx__vertex_sub(&e3, &v3);
fex = fabs(e1.x);
fey = fabs(e1.y);
fez = fabs(e1.z);
AXISTEST_X01(e1.z, e1.y, fez, fey);
AXISTEST_Y02(e1.z, e1.x, fez, fex);
AXISTEST_Z12(e1.y, e1.x, fey, fex);
fex = fabs(e2.x);
fey = fabs(e2.y);
fez = fabs(e2.z);
AXISTEST_X01(e2.z, e2.y, fez, fey);
AXISTEST_Y02(e2.z, e2.x, fez, fex);
AXISTEST_Z0(e2.y, e2.x, fey, fex);
fex = fabs(e3.x);
fey = fabs(e3.y);
fez = fabs(e3.z);
AXISTEST_X2(e3.z, e3.y, fez, fey);
AXISTEST_Y1(e3.z, e3.x, fez, fex);
AXISTEST_Z12(e3.y, e3.x, fey, fex);
VX_FINDMINMAX(v1.x, v2.x, v3.x, min, max);
if (min > halfboxsize.x || max < -halfboxsize.x) {
return false;
}
VX_FINDMINMAX(v1.y, v2.y, v3.y, min, max);
if (min > halfboxsize.y || max < -halfboxsize.y) {
return false;
}
VX_FINDMINMAX(v1.z, v2.z, v3.z, min, max);
if (min > halfboxsize.z || max < -halfboxsize.z) {
return false;
}
normal = vx__vertex_cross(&e1, &e2);
d = -vx__vertex_dot(&normal, &v1);
if (!vx__plane_box_overlap(&normal, d, &halfboxsize)) {
return false;
}
return true;
}
#undef AXISTEST_X2
#undef AXISTEST_X01
#undef AXISTEST_Y1
#undef AXISTEST_Y02
#undef AXISTEST_Z0
#undef AXISTEST_Z12
float vx__triangle_area(vx_triangle_t* triangle) {
vx_vertex_t ab = triangle->p2;
vx_vertex_t ac = triangle->p3;
vx__vertex_sub(&ab, &triangle->p1);
vx__vertex_sub(&ac, &triangle->p1);
float a0 = ab.y * ac.z - ab.z * ac.y;
float a1 = ab.z * ac.x - ab.x * ac.z;
float a2 = ab.x * ac.y - ab.y * ac.x;
return sqrtf(powf(a0, 2.f) + powf(a1, 2.f) + powf(a2, 2.f)) * 0.5f;
}
void vx__aabb_init(vx_aabb_t* aabb)
{
aabb->max.x = aabb->max.y = aabb->max.z = -INFINITY;
aabb->min.x = aabb->min.y = aabb->min.z = INFINITY;
}
vx_aabb_t vx__triangle_aabb(vx_triangle_t* triangle)
{
vx_aabb_t aabb;
vx__aabb_init(&aabb);
aabb.max.x = VX_MAX(aabb.max.x, triangle->p1.x); aabb.max.x = VX_MAX(aabb.max.x,
triangle->p2.x); aabb.max.x = VX_MAX(aabb.max.x, triangle->p3.x);
aabb.max.y = VX_MAX(aabb.max.y, triangle->p1.y); aabb.max.y = VX_MAX(aabb.max.y,
triangle->p2.y); aabb.max.y = VX_MAX(aabb.max.y, triangle->p3.y);
aabb.max.z = VX_MAX(aabb.max.z, triangle->p1.z); aabb.max.z = VX_MAX(aabb.max.z,
triangle->p2.z); aabb.max.z = VX_MAX(aabb.max.z, triangle->p3.z);
aabb.min.x = VX_MIN(aabb.min.x, triangle->p1.x); aabb.min.x = VX_MIN(aabb.min.x,
triangle->p2.x); aabb.min.x = VX_MIN(aabb.min.x, triangle->p3.x);
aabb.min.y = VX_MIN(aabb.min.y, triangle->p1.y); aabb.min.y = VX_MIN(aabb.min.y,
triangle->p2.y); aabb.min.y = VX_MIN(aabb.min.y, triangle->p3.y);
aabb.min.z = VX_MIN(aabb.min.z, triangle->p1.z); aabb.min.z = VX_MIN(aabb.min.z,
triangle->p2.z); aabb.min.z = VX_MIN(aabb.min.z, triangle->p3.z);
return aabb;
}
vx_vertex_t vx__aabb_center(vx_aabb_t* a)
{
vx_vertex_t boxcenter = a->min;
vx__vertex_add(&boxcenter, &a->max);
vx__vertex_multiply(&boxcenter, 0.5f);
return boxcenter;
}
vx_vertex_t vx__aabb_half_size(vx_aabb_t* a)
{
vx_vertex_t size;
size.x = fabs(a->max.x - a->min.x) * 0.5f;
size.y = fabs(a->max.y - a->min.y) * 0.5f;
size.z = fabs(a->max.z - a->min.z) * 0.5f;
return size;
}
vx_aabb_t vx__aabb_merge(vx_aabb_t* a, vx_aabb_t* b)
{
vx_aabb_t merge;
merge.min.x = VX_MIN(a->min.x, b->min.x);
merge.min.y = VX_MIN(a->min.y, b->min.y);
merge.min.z = VX_MIN(a->min.z, b->min.z);
merge.max.x = VX_MAX(a->max.x, b->max.x);
merge.max.y = VX_MAX(a->max.y, b->max.y);
merge.max.z = VX_MAX(a->max.z, b->max.z);
return merge;
}
size_t vx__vertex_hash(vx_vertex_t pos, size_t n)
{
size_t a = (size_t)(pos.x * 73856093);
size_t b = (size_t)(pos.y * 19349663);
size_t c = (size_t)(pos.z * 83492791);
return (a ^ b ^ c) % n;
}
void vx__add_voxel(vx_mesh_t* mesh,
vx_vertex_t* pos,
float* vertices)
{
for (size_t i = 0; i < 8; ++i) {
size_t index = i+mesh->nvertices;
mesh->vertices[index].x = vertices[i*3+0] + pos->x;
mesh->vertices[index].y = vertices[i*3+1] + pos->y;
mesh->vertices[index].z = vertices[i*3+2] + pos->z;
}
int j = -1;
for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
if (i % 6 == 0) {
j++;
}
mesh->normalindices[i+mesh->nindices] = vx_normal_indices[j];
}
for (size_t i = 0; i < VOXELIZER_INDICES_SIZE; ++i) {
mesh->indices[i+mesh->nindices] = vx_voxel_indices[i] + mesh->nvertices;
}
mesh->nindices += VOXELIZER_INDICES_SIZE;
mesh->nvertices += 8;
}
vx_mesh_t* vx_voxelize(vx_mesh_t* m,
float voxelsizex,
float voxelsizey,
float voxelsizez,
float precision)
{
vx_mesh_t* outmesh = NULL;
vx_hash_table_t* table = NULL;
size_t voxels = 0;
float halfsizex = voxelsizex * 0.5f;
float halfsizey = voxelsizey * 0.5f;
float halfsizez = voxelsizez * 0.5f;
table = vx__hash_table_alloc(VOXELIZER_HASH_TABLE_SIZE);
for (int i = 0; i < m->nindices; i += 3) {
vx_triangle_t triangle;
VX_ASSERT(m->indices[i+0] < m->nvertices);
VX_ASSERT(m->indices[i+1] < m->nvertices);
VX_ASSERT(m->indices[i+2] < m->nvertices);
triangle.p1 = m->vertices[m->indices[i+0]];
triangle.p2 = m->vertices[m->indices[i+1]];
triangle.p3 = m->vertices[m->indices[i+2]];
if (vx__triangle_area(&triangle) < VOXELIZER_EPSILON) {
// triangle with 0 area
continue;
}
vx_aabb_t aabb = vx__triangle_aabb(&triangle);
aabb.min.x = vx__map_to_voxel(aabb.min.x, voxelsizex, true);
aabb.min.y = vx__map_to_voxel(aabb.min.y, voxelsizey, true);
aabb.min.z = vx__map_to_voxel(aabb.min.z, voxelsizez, true);
aabb.max.x = vx__map_to_voxel(aabb.max.x, voxelsizex, false);
aabb.max.y = vx__map_to_voxel(aabb.max.y, voxelsizey, false);
aabb.max.z = vx__map_to_voxel(aabb.max.z, voxelsizez, false);
for (float x = aabb.min.x; x < aabb.max.x; x += voxelsizex) {
for (float y = aabb.min.y; y < aabb.max.y; y += voxelsizey) {
for (float z = aabb.min.z; z < aabb.max.z; z += voxelsizez) {
vx_aabb_t saabb;
saabb.min.x = x - halfsizex;
saabb.min.y = y - halfsizey;
saabb.min.z = z - halfsizez;
saabb.max.x = x + halfsizex;
saabb.max.y = y + halfsizey;
saabb.max.z = z + halfsizez;
vx_vertex_t boxcenter = vx__aabb_center(&saabb);
vx_vertex_t halfsize = vx__aabb_half_size(&saabb);
// HACK: some holes might appear, this
// precision factor reduces the artifact
halfsize.x += precision;
halfsize.y += precision;
halfsize.z += precision;
if (vx__triangle_box_overlap(boxcenter, halfsize, triangle)) {
vx_vertex_t* nodedata = VX_MALLOC(vx_vertex_t, 1);
*nodedata = boxcenter;
size_t hash = vx__vertex_hash(boxcenter, VOXELIZER_HASH_TABLE_SIZE);
bool insert = vx__hash_table_insert(table,
hash,
nodedata,
vx__vertex_comp_func);
if (insert) {
voxels++;
}
}
}
}
}
}
outmesh = VX_MALLOC(vx_mesh_t, 1);
size_t nvertices = voxels * 8;
size_t nindices = voxels * VOXELIZER_INDICES_SIZE;
outmesh->nnormals = VOXELIZER_NORMAL_INDICES_SIZE;
outmesh->vertices = VX_CALLOC(vx_vertex_t, nvertices);
outmesh->normals = VX_CALLOC(vx_vertex_t, 6);
outmesh->indices = VX_CALLOC(unsigned int, nindices);
outmesh->normalindices = VX_CALLOC(unsigned int, nindices);
outmesh->nindices = 0;
outmesh->nvertices = 0;
memcpy(outmesh->normals, vx_normals, 18 * sizeof(float));
float vertices[24] = {
-halfsizex, halfsizey, halfsizez,
-halfsizex, -halfsizey, halfsizez,
halfsizex, -halfsizey, halfsizez,
halfsizex, halfsizey, halfsizez,
-halfsizex, halfsizey, -halfsizez,
-halfsizex, -halfsizey, -halfsizez,
halfsizex, -halfsizey, -halfsizez,
halfsizex, halfsizey, -halfsizez,
};
for (size_t i = 0; i < table->size; ++i) {
if (table->elements[i] != NULL) {
vx_hash_table_node_t* node = table->elements[i];
if (!node) {
continue;
}
vx_vertex_t* p = (vx_vertex_t*) node->data;
vx__add_voxel(outmesh, p, vertices);
while (node->next) {
node = node->next;
p = (vx_vertex_t*) node->data;
vx__add_voxel(outmesh, p, vertices);
}
}
}
vx__hash_table_free(table, true);
return outmesh;
}
#undef VOXELIZER_EPSILON
#undef VOXELIZER_INDICES_SIZE
#undef VOXELIZER_HASH_TABLE_SIZE
#endif // VX_VOXELIZER_IMPLEMENTATION

26
experimental/README.md Normal file
View File

@@ -0,0 +1,26 @@
# Experimental code for .obj loader.
* Multi-threaded optimized parser : tinyobj_loader_opt.h
## Requirements
* C++-11 compiler
## How to build
```
$ premak5 gmake
```
## Compile options
* zstd compressed .obj support. `--with-zstd` premake option.
* gzip compressed .obj support. `--with-zlib` premake option.
## Notes on AMD GPU + Linux
You may need to link with libdrm(`-ldrm`).
## Licenses
* lfpAlloc : MIT license.

View File

@@ -0,0 +1,89 @@
#ifndef LF_POOL_ALLOCATOR
#define LF_POOL_ALLOCATOR
#include <memory>
#include <thread>
#include <lfpAlloc/PoolDispatcher.hpp>
namespace lfpAlloc {
template <typename T, std::size_t NumPools = 70>
class lfpAllocator {
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = T const&;
template <typename U>
struct rebind {
typedef lfpAllocator<U, NumPools> other;
};
lfpAllocator() {}
template <typename U>
lfpAllocator(lfpAllocator<U, NumPools>&&) noexcept {}
template <typename U>
lfpAllocator(const lfpAllocator<U, NumPools>&) noexcept {}
T* allocate(std::size_t count) {
if (sizeof(T) * count <=
alignof(std::max_align_t) * NumPools - sizeof(void*)) {
return reinterpret_cast<T*>(
dispatcher_.allocate(sizeof(T) * count));
} else {
return new T[count];
}
}
void deallocate(T* p, std::size_t count) noexcept {
if (sizeof(T) * count <=
alignof(std::max_align_t) * NumPools - sizeof(void*)) {
dispatcher_.deallocate(p, sizeof(T) * count);
} else {
delete[] p;
}
}
// Should not be required, but allocator_traits is not complete in
// gcc 4.9.1
template <typename U>
void destroy(U* p) {
p->~U();
}
template <typename U, typename... Args>
void construct(U* p, Args&&... args) {
new (p) U(std::forward<Args>(args)...);
}
template <typename Ty, typename U, std::size_t N, std::size_t M>
friend bool operator==(const lfpAllocator<Ty, N>&,
const lfpAllocator<U, M>&) noexcept;
template <typename U, std::size_t M>
friend class lfpAllocator;
private:
static PoolDispatcher<NumPools> dispatcher_;
};
template <typename T, std::size_t N>
PoolDispatcher<N> lfpAllocator<T, N>::dispatcher_;
template <typename T, typename U, std::size_t N, std::size_t M>
inline bool operator==(const lfpAllocator<T, N>&,
const lfpAllocator<U, M>&) noexcept {
return N == M;
}
template <typename T, typename U, std::size_t N, std::size_t M>
inline bool operator!=(const lfpAllocator<T, N>& left,
const lfpAllocator<U, M>& right) noexcept {
return !(left == right);
}
}
#endif

View File

@@ -0,0 +1,116 @@
#ifndef LF_POOL_ALLOC_CHUNK_LIST
#define LF_POOL_ALLOC_CHUNK_LIST
#include <cstdint>
#include <atomic>
#include <type_traits>
#ifndef LFP_ALLOW_BLOCKING
static_assert(ATOMIC_POINTER_LOCK_FREE == 2,
"Atomic pointer is not lock-free.");
#endif
namespace lfpAlloc {
template <std::size_t Size>
struct Cell {
uint8_t val_[Size];
Cell* next_ = this + 1;
};
// For small types (less than the size of void*), no additional
// space is needed, so union val_ with next_ to avoid overhead.
template <>
struct Cell<0> {
Cell() : next_{this + 1} {}
union {
uint8_t val_[sizeof(Cell*)];
Cell* next_;
};
};
template <std::size_t Size, std::size_t AllocationsPerChunk>
struct Chunk {
Chunk() noexcept {
auto& last = memBlock_[AllocationsPerChunk - 1];
last.next_ = nullptr;
}
Cell<Size> memBlock_[AllocationsPerChunk];
};
template <typename T>
struct Node {
Node() : val_(), next_(nullptr) {}
Node(const T& val) : val_(val), next_(nullptr) {}
T val_;
std::atomic<Node<T>*> next_;
};
template <std::size_t Size, std::size_t AllocationsPerChunk>
class ChunkList {
static constexpr auto CellSize =
(Size > sizeof(void*)) ? Size - sizeof(void*) : 0;
using Chunk_t = Chunk<CellSize, AllocationsPerChunk>;
using Cell_t = Cell<CellSize>;
using ChunkNode = Node<Chunk_t>;
using CellNode = Node<Cell_t*>;
public:
static ChunkList& getInstance() {
static ChunkList c;
return c;
}
Cell_t* allocateChain() {
CellNode* recentHead = head_.load();
CellNode* currentNext = nullptr;
do {
// If there are no available chains, allocate a new chunk
if (!recentHead) {
ChunkNode* currentHandle;
// Make a new node
auto newChunk = new ChunkNode();
// Add the chunk to the chain
do {
currentHandle = handle_.load();
newChunk->next_ = currentHandle;
} while (
!handle_.compare_exchange_weak(currentHandle, newChunk));
return &newChunk->val_.memBlock_[0];
}
currentNext = recentHead->next_;
} while (!head_.compare_exchange_weak(recentHead, currentNext));
auto retnValue = recentHead->val_;
delete recentHead;
return retnValue;
}
void deallocateChain(Cell_t* newCell) {
if (!newCell) {
return;
}
CellNode* currentHead = head_.load();
// Construct a new node to be added to the linked list
CellNode* newHead = new CellNode(newCell);
// Add the chain to the linked list
do {
newHead->next_.store(currentHead, std::memory_order_release);
} while (!head_.compare_exchange_weak(currentHead, newHead));
}
private:
ChunkList() : handle_(nullptr), head_(nullptr) {}
std::atomic<ChunkNode*> handle_;
std::atomic<CellNode*> head_;
};
}
#endif

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Adam Schwalm
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,48 @@
#ifndef LF_POOL_ALLOC_POOL
#define LF_POOL_ALLOC_POOL
#include <lfpAlloc/Utils.hpp>
#include <lfpAlloc/ChunkList.hpp>
namespace lfpAlloc {
template <std::size_t Size, std::size_t AllocationsPerChunk>
class Pool {
using ChunkList_t = ChunkList<Size, AllocationsPerChunk>;
public:
static constexpr auto CellSize =
(Size > sizeof(void*)) ? Size - sizeof(void*) : 0;
using Cell_t = Cell<CellSize>;
Pool() : head_(nullptr) {}
~Pool() { ChunkList_t::getInstance().deallocateChain(head_); }
void* allocate() {
// Head loaded from head_
Cell_t* currentHead = head_;
Cell_t* next;
// Out of cells to allocate
if (!currentHead) {
currentHead = ChunkList_t::getInstance().allocateChain();
}
next = currentHead->next_;
head_ = next;
return &currentHead->val_;
}
void deallocate(void* p) noexcept {
auto newHead = reinterpret_cast<Cell_t*>(p);
Cell_t* currentHead = head_;
newHead->next_ = currentHead;
head_ = newHead;
}
private:
Cell_t* head_;
};
}
#endif

View File

@@ -0,0 +1,79 @@
#ifndef LF_POOL_DISPATCHER
#define LF_POOL_DISPATCHER
#include <tuple>
#include <cassert>
#include <cstddef>
#include <lfpAlloc/Pool.hpp>
#ifndef LFP_ALLOCATIONS_PER_CHUNK
#define LFP_ALLOCATIONS_PER_CHUNK 64 * 100
#endif
namespace lfpAlloc {
namespace detail {
template <std::size_t Num, uint16_t... Ts>
struct Pools : Pools<Num - 1, alignof(std::max_align_t) * Num, Ts...> {};
template <uint16_t... Size>
struct Pools<0, Size...> {
using type = std::tuple<Pool<Size, LFP_ALLOCATIONS_PER_CHUNK>...>;
};
}
template <std::size_t NumPools>
class PoolDispatcher {
public:
void* allocate(std::size_t size) { return dispatchAllocate<0>(size); }
void deallocate(void* p, std::size_t size) noexcept {
dispatchDeallocate<0>(p, size);
}
private:
thread_local static typename detail::Pools<NumPools>::type pools_;
static_assert(NumPools > 0, "Invalid number of pools");
template <std::size_t Index>
typename std::enable_if <
Index<NumPools, void*>::type
dispatchAllocate(std::size_t const& requestSize) {
if (requestSize <= std::get<Index>(pools_).CellSize) {
return std::get<Index>(pools_).allocate();
} else {
return dispatchAllocate<Index + 1>(requestSize);
}
}
template <std::size_t Index>
typename std::enable_if<!(Index < NumPools), void*>::type
dispatchAllocate(std::size_t const&) {
assert(false && "Invalid allocation size.");
return nullptr;
}
template <std::size_t Index>
typename std::enable_if <
Index<NumPools>::type
dispatchDeallocate(void* p, std::size_t const& requestSize) noexcept {
if (requestSize <= std::get<Index>(pools_).CellSize) {
std::get<Index>(pools_).deallocate(p);
} else {
dispatchDeallocate<Index + 1>(p, requestSize);
}
}
template <std::size_t Index>
typename std::enable_if<!(Index < NumPools)>::type
dispatchDeallocate(void*, std::size_t const&) noexcept {
assert(false && "Invalid deallocation size.");
}
};
template <std::size_t NumPools>
thread_local typename detail::Pools<NumPools>::type
PoolDispatcher<NumPools>::pools_;
}
#endif

View File

@@ -0,0 +1,20 @@
#include <cstdint>
namespace lfpAlloc {
namespace detail {
template <std::size_t Val, std::size_t base = 2>
struct Log {
enum { value = 1 + Log<Val / base, base>::value };
};
template <std::size_t base>
struct Log<1, base> {
enum { value = 0 };
};
template <std::size_t base>
struct Log<0, base> {
enum { value = 0 };
};
}
}

94
experimental/premake5.lua Normal file
View File

@@ -0,0 +1,94 @@
newoption {
trigger = "with-zlib",
description = "Build with zlib."
}
newoption {
trigger = "with-zstd",
description = "Build with ZStandard compression."
}
newoption {
trigger = "clang",
description = "Use clang compiler."
}
newoption {
trigger = "asan",
description = "Enable AddressSanitizer(gcc or clang only)."
}
solution "objview"
-- location ( "build" )
configurations { "Release", "Debug" }
platforms {"native", "x64", "x32"}
project "objview"
kind "ConsoleApp"
language "C++"
files { "viewer.cc", "trackball.cc" }
includedirs { "./" }
includedirs { "../../" }
flags { "c++11" }
if _OPTIONS['clang'] then
toolset "clang"
end
if _OPTIONS['with-zlib'] then
defines { 'ENABLE_ZLIB' }
links { 'z' }
end
if _OPTIONS['asan'] then
buildoptions { '-fsanitize=address' }
linkoptions { '-fsanitize=address' }
end
if _OPTIONS['with-zstd'] then
print("with-zstd")
defines { 'ENABLE_ZSTD' }
-- Set path to zstd installed dir.
includedirs { '$$HOME/local/include' }
libdirs { '$$HOME/local/lib' }
links { 'zstd' }
end
-- Uncomment if you want address sanitizer(gcc/clang only)
--buildoptions { "-fsanitize=address" }
--linkoptions { "-fsanitize=address" }
configuration { "linux" }
linkoptions { "`pkg-config --libs glfw3`" }
links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" }
linkoptions { "-pthread" }
configuration { "windows" }
-- Path to GLFW3
includedirs { '../../../local/glfw-3.2.bin.WIN64/include' }
libdirs { '../../../local/glfw-3.2.bin.WIN64/lib-vc2015' }
-- Path to GLEW
includedirs { '../../../local/glew-1.13.0/include' }
libdirs { '../../../local/glew-1.13.0/lib/Release/x64' }
links { "glfw3", "glew32", "gdi32", "winmm", "user32", "glu32","opengl32", "kernel32" }
defines { "_CRT_SECURE_NO_WARNINGS" }
defines { "NOMINMAX" }
configuration { "macosx" }
includedirs { "/usr/local/include" }
buildoptions { "-Wno-deprecated-declarations" }
libdirs { "/usr/local/lib" }
links { "glfw3", "GLEW" }
linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" }
configuration "Debug"
defines { "DEBUG" }
flags { "Symbols"}
configuration "Release"
defines { "NDEBUG" }
flags { "Optimize"}

File diff suppressed because it is too large Load Diff

292
experimental/trackball.cc Normal file
View File

@@ -0,0 +1,292 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* Trackball code:
*
* Implementation of a virtual trackball.
* Implemented by Gavin Bell, lots of ideas from Thant Tessman and
* the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
*
* Vector manip code:
*
* Original code from:
* David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
*
* Much mucking with by:
* Gavin Bell
*/
#include <math.h>
#include "trackball.h"
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
#define TRACKBALLSIZE (0.8)
/*
* Local function prototypes (not defined in trackball.h)
*/
static float tb_project_to_sphere(float, float, float);
static void normalize_quat(float[4]);
static void vzero(float *v) {
v[0] = 0.0;
v[1] = 0.0;
v[2] = 0.0;
}
static void vset(float *v, float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
static void vsub(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] - src2[0];
dst[1] = src1[1] - src2[1];
dst[2] = src1[2] - src2[2];
}
static void vcopy(const float *v1, float *v2) {
int i;
for (i = 0; i < 3; i++)
v2[i] = v1[i];
}
static void vcross(const float *v1, const float *v2, float *cross) {
float temp[3];
temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
vcopy(temp, cross);
}
static float vlength(const float *v) {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
static void vscale(float *v, float div) {
v[0] *= div;
v[1] *= div;
v[2] *= div;
}
static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); }
static float vdot(const float *v1, const float *v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
static void vadd(const float *src1, const float *src2, float *dst) {
dst[0] = src1[0] + src2[0];
dst[1] = src1[1] + src2[1];
dst[2] = src1[2] + src2[2];
}
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) {
float a[3]; /* Axis of rotation */
float phi; /* how much to rotate about axis */
float p1[3], p2[3], d[3];
float t;
if (p1x == p2x && p1y == p2y) {
/* Zero rotation */
vzero(q);
q[3] = 1.0;
return;
}
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y));
vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y));
/*
* Now, we want the cross product of P1 and P2
*/
vcross(p2, p1, a);
/*
* Figure out how much to rotate around that axis.
*/
vsub(p1, p2, d);
t = vlength(d) / (2.0 * TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0)
t = 1.0;
if (t < -1.0)
t = -1.0;
phi = 2.0 * asin(t);
axis_to_quat(a, phi, q);
}
/*
* Given an axis and angle, compute quaternion.
*/
void axis_to_quat(float a[3], float phi, float q[4]) {
vnormal(a);
vcopy(a, q);
vscale(q, sin(phi / 2.0));
q[3] = cos(phi / 2.0);
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
static float tb_project_to_sphere(float r, float x, float y) {
float d, t, z;
d = sqrt(x * x + y * y);
if (d < r * 0.70710678118654752440) { /* Inside sphere */
z = sqrt(r * r - d * d);
} else { /* On hyperbola */
t = r / 1.41421356237309504880;
z = t * t / d;
}
return z;
}
/*
* Given two rotations, e1 and e2, expressed as quaternion rotations,
* figure out the equivalent single rotation and stuff it into dest.
*
* This routine also normalizes the result every RENORMCOUNT times it is
* called, to keep error from creeping in.
*
* NOTE: This routine is written so that q1 or q2 may be the same
* as dest (or each other).
*/
#define RENORMCOUNT 97
void add_quats(float q1[4], float q2[4], float dest[4]) {
static int count = 0;
float t1[4], t2[4], t3[4];
float tf[4];
vcopy(q1, t1);
vscale(t1, q2[3]);
vcopy(q2, t2);
vscale(t2, q1[3]);
vcross(q2, q1, t3);
vadd(t1, t2, tf);
vadd(t3, tf, tf);
tf[3] = q1[3] * q2[3] - vdot(q1, q2);
dest[0] = tf[0];
dest[1] = tf[1];
dest[2] = tf[2];
dest[3] = tf[3];
if (++count > RENORMCOUNT) {
count = 0;
normalize_quat(dest);
}
}
/*
* Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
* If they don't add up to 1.0, dividing by their magnitued will
* renormalize them.
*
* Note: See the following for more information on quaternions:
*
* - Shoemake, K., Animating rotation with quaternion curves, Computer
* Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
* - Pletinckx, D., Quaternion calculus as a basic tool in computer
* graphics, The Visual Computer 5, 2-13, 1989.
*/
static void normalize_quat(float q[4]) {
int i;
float mag;
mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
for (i = 0; i < 4; i++)
q[i] /= mag;
}
/*
* Build a rotation matrix, given a quaternion rotation.
*
*/
void build_rotmatrix(float m[4][4], const float q[4]) {
m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
m[0][3] = 0.0;
m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
m[1][3] = 0.0;
m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}

75
experimental/trackball.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* (c) Copyright 1993, 1994, Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the above
* copyright notice appear in all copies and that both the copyright notice
* and this permission notice appear in supporting documentation, and that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
/*
* trackball.h
* A virtual trackball implementation
* Written by Gavin Bell for Silicon Graphics, November 1988.
*/
/*
* Pass the x and y coordinates of the last and current positions of
* the mouse, scaled so they are from (-1.0 ... 1.0).
*
* The resulting rotation is returned as a quaternion rotation in the
* first paramater.
*/
void trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
void negate_quat(float *q, float *qn);
/*
* Given two quaternions, add them together to get a third quaternion.
* Adding quaternions to get a compound rotation is analagous to adding
* translations to get a compound translation. When incrementally
* adding rotations, the first argument here should be the new
* rotation, the second and third the total rotation (which will be
* over-written with the resulting new total rotation).
*/
void add_quats(float *q1, float *q2, float *dest);
/*
* A useful function, builds a rotation matrix in Matrix based on
* given quaternion.
*/
void build_rotmatrix(float m[4][4], const float q[4]);
/*
* This function computes a quaternion based on an axis (defined by
* the given vector) and an angle about which to rotate. The angle is
* expressed in radians. The result is put into the third argument.
*/
void axis_to_quat(float a[3], float phi, float q[4]);

748
experimental/viewer.cc Normal file
View File

@@ -0,0 +1,748 @@
//
// Simple .obj viewer(vertex only)
//
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <cmath>
#include <cassert>
#include <cstring>
#include <algorithm>
#if defined(ENABLE_ZLIB)
#include <zlib.h>
#endif
#if defined(ENABLE_ZSTD)
#include <zstd.h>
#endif
#include <GL/glew.h>
#ifdef __APPLE__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <GLFW/glfw3.h>
#include "trackball.h"
#define TINYOBJ_LOADER_OPT_IMPLEMENTATION
#include "tinyobj_loader_opt.h"
typedef struct {
GLuint vb; // vertex buffer
int numTriangles;
} DrawObject;
std::vector<DrawObject> gDrawObjects;
int width = 768;
int height = 768;
double prevMouseX, prevMouseY;
bool mouseLeftPressed;
bool mouseMiddlePressed;
bool mouseRightPressed;
float curr_quat[4];
float prev_quat[4];
float eye[3], lookat[3], up[3];
GLFWwindow* window;
void CheckErrors(std::string desc) {
GLenum e = glGetError();
if (e != GL_NO_ERROR) {
fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
exit(20);
}
}
void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
float v10[3];
v10[0] = v1[0] - v0[0];
v10[1] = v1[1] - v0[1];
v10[2] = v1[2] - v0[2];
float v20[3];
v20[0] = v2[0] - v0[0];
v20[1] = v2[1] - v0[1];
v20[2] = v2[2] - v0[2];
N[0] = v20[1] * v10[2] - v20[2] * v10[1];
N[1] = v20[2] * v10[0] - v20[0] * v10[2];
N[2] = v20[0] * v10[1] - v20[1] * v10[0];
float len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
N[0] /= len;
N[1] /= len;
}
}
const char *mmap_file(size_t *len, const char* filename)
{
(*len) = 0;
#ifdef _WIN32
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
assert(file != INVALID_HANDLE_VALUE);
HANDLE fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
assert(fileMapping != INVALID_HANDLE_VALUE);
LPVOID fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0);
auto fileMapViewChar = (const char*)fileMapView;
assert(fileMapView != NULL);
LARGE_INTEGER fileSize;
fileSize.QuadPart = 0;
GetFileSizeEx(file, &fileSize);
(*len) = static_cast<size_t>(fileSize.QuadPart);
return fileMapViewChar;
#else
FILE* f = fopen(filename, "rb" );
if (!f) {
fprintf(stderr, "Failed to open file : %s\n", filename);
return nullptr;
}
fseek(f, 0, SEEK_END);
long fileSize = ftell(f);
fclose(f);
if (fileSize < 16) {
fprintf(stderr, "Empty or invalid .obj : %s\n", filename);
return nullptr;
}
struct stat sb;
char *p;
int fd;
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror ("open");
return nullptr;
}
if (fstat (fd, &sb) == -1) {
perror ("fstat");
return nullptr;
}
if (!S_ISREG (sb.st_mode)) {
fprintf (stderr, "%s is not a file\n", "lineitem.tbl");
return nullptr;
}
p = (char*)mmap (0, fileSize, PROT_READ, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
perror ("mmap");
return nullptr;
}
if (close (fd) == -1) {
perror ("close");
return nullptr;
}
(*len) = fileSize;
return p;
#endif
}
bool gz_load(std::vector<char>* buf, const char* filename)
{
#ifdef ENABLE_ZLIB
gzFile file;
file = gzopen (filename, "r");
if (! file) {
fprintf (stderr, "gzopen of '%s' failed: %s.\n", filename,
strerror (errno));
exit (EXIT_FAILURE);
return false;
}
while (1) {
int err;
int bytes_read;
unsigned char buffer[1024];
bytes_read = gzread (file, buffer, 1024);
buf->insert(buf->end(), buffer, buffer + 1024);
//printf ("%s", buffer);
if (bytes_read < 1024) {
if (gzeof (file)) {
break;
}
else {
const char * error_string;
error_string = gzerror (file, & err);
if (err) {
fprintf (stderr, "Error: %s.\n", error_string);
exit (EXIT_FAILURE);
return false;
}
}
}
}
gzclose (file);
return true;
#else
return false;
#endif
}
#ifdef ENABLE_ZSTD
static off_t fsize_X(const char *filename)
{
struct stat st;
if (stat(filename, &st) == 0) return st.st_size;
/* error */
printf("stat: %s : %s \n", filename, strerror(errno));
exit(1);
}
static FILE* fopen_X(const char *filename, const char *instruction)
{
FILE* const inFile = fopen(filename, instruction);
if (inFile) return inFile;
/* error */
printf("fopen: %s : %s \n", filename, strerror(errno));
exit(2);
}
static void* malloc_X(size_t size)
{
void* const buff = malloc(size);
if (buff) return buff;
/* error */
printf("malloc: %s \n", strerror(errno));
exit(3);
}
#endif
bool zstd_load(std::vector<char>* buf, const char* filename)
{
#ifdef ENABLE_ZSTD
off_t const buffSize = fsize_X(filename);
FILE* const inFile = fopen_X(filename, "rb");
void* const buffer = malloc_X(buffSize);
size_t const readSize = fread(buffer, 1, buffSize, inFile);
if (readSize != (size_t)buffSize) {
printf("fread: %s : %s \n", filename, strerror(errno));
exit(4);
}
fclose(inFile);
unsigned long long const rSize = ZSTD_getDecompressedSize(buffer, buffSize);
if (rSize==0) {
printf("%s : original size unknown \n", filename);
exit(5);
}
buf->resize(rSize);
size_t const dSize = ZSTD_decompress(buf->data(), rSize, buffer, buffSize);
if (dSize != rSize) {
printf("error decoding %s : %s \n", filename, ZSTD_getErrorName(dSize));
exit(7);
}
free(buffer);
return true;
#else
return false;
#endif
}
const char* get_file_data(size_t *len, const char* filename)
{
const char *ext = strrchr(filename, '.');
size_t data_len = 0;
const char* data = nullptr;
if (strcmp(ext, ".gz") == 0) {
// gzipped data.
std::vector<char> buf;
bool ret = gz_load(&buf, filename);
if (ret) {
char *p = static_cast<char*>(malloc(buf.size() + 1)); // @fixme { implement deleter }
memcpy(p, &buf.at(0), buf.size());
p[buf.size()] = '\0';
data = p;
data_len = buf.size();
}
} else if (strcmp(ext, ".zst") == 0) {
printf("zstd\n");
// Zstandard data.
std::vector<char> buf;
bool ret = zstd_load(&buf, filename);
if (ret) {
char *p = static_cast<char*>(malloc(buf.size() + 1)); // @fixme { implement deleter }
memcpy(p, &buf.at(0), buf.size());
p[buf.size()] = '\0';
data = p;
data_len = buf.size();
}
} else {
data = mmap_file(&data_len, filename);
}
(*len) = data_len;
return data;
}
bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int num_threads, bool verbose)
{
tinyobj_opt::attrib_t attrib;
std::vector<tinyobj_opt::shape_t> shapes;
std::vector<tinyobj_opt::material_t> materials;
auto load_t_begin = std::chrono::high_resolution_clock::now();
size_t data_len = 0;
const char* data = get_file_data(&data_len, filename);
if (data == nullptr) {
printf("failed to load file\n");
exit(-1);
return false;
}
auto load_t_end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> load_ms = load_t_end - load_t_begin;
if (verbose) {
std::cout << "filesize: " << data_len << std::endl;
std::cout << "load time: " << load_ms.count() << " [msecs]" << std::endl;
}
tinyobj_opt::LoadOption option;
option.req_num_threads = num_threads;
option.verbose = verbose;
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
if (!ret) {
std::cerr << "Failed to parse .obj" << std::endl;
return false;
}
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
//std::cout << "vertices.size() = " << attrib.vertices.size() << std::endl;
//std::cout << "normals.size() = " << attrib.normals.size() << std::endl;
{
DrawObject o;
std::vector<float> vb; // pos(3float), normal(3float), color(3float)
size_t face_offset = 0;
for (size_t v = 0; v < attrib.face_num_verts.size(); v++) {
assert(attrib.face_num_verts[v] % 3 == 0); // assume all triangle face(multiple of 3).
for (size_t f = 0; f < attrib.face_num_verts[v] / 3; f++) {
tinyobj_opt::index_t idx0 = attrib.indices[face_offset+3*f+0];
tinyobj_opt::index_t idx1 = attrib.indices[face_offset+3*f+1];
tinyobj_opt::index_t idx2 = attrib.indices[face_offset+3*f+2];
float v[3][3];
for (int k = 0; k < 3; k++) {
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
assert(f0 >= 0);
assert(f1 >= 0);
assert(f2 >= 0);
v[0][k] = attrib.vertices[3*f0+k];
v[1][k] = attrib.vertices[3*f1+k];
v[2][k] = attrib.vertices[3*f2+k];
bmin[k] = std::min(v[0][k], bmin[k]);
bmin[k] = std::min(v[1][k], bmin[k]);
bmin[k] = std::min(v[2][k], bmin[k]);
bmax[k] = std::max(v[0][k], bmax[k]);
bmax[k] = std::max(v[1][k], bmax[k]);
bmax[k] = std::max(v[2][k], bmax[k]);
}
float n[3][3];
if (attrib.normals.size() > 0) {
int nf0 = idx0.normal_index;
int nf1 = idx1.normal_index;
int nf2 = idx2.normal_index;
if (nf0 >= 0 && nf1 >= 0 && nf2 >= 0) {
assert(3*nf0+2 < attrib.normals.size());
assert(3*nf1+2 < attrib.normals.size());
assert(3*nf2+2 < attrib.normals.size());
for (int k = 0; k < 3; k++) {
n[0][k] = attrib.normals[3*nf0+k];
n[1][k] = attrib.normals[3*nf1+k];
n[2][k] = attrib.normals[3*nf2+k];
}
} else {
// compute geometric normal
CalcNormal(n[0], v[0], v[1], v[2]);
n[1][0] = n[0][0]; n[1][1] = n[0][1]; n[1][2] = n[0][2];
n[2][0] = n[0][0]; n[2][1] = n[0][1]; n[2][2] = n[0][2];
}
} else {
// compute geometric normal
CalcNormal(n[0], v[0], v[1], v[2]);
n[1][0] = n[0][0]; n[1][1] = n[0][1]; n[1][2] = n[0][2];
n[2][0] = n[0][0]; n[2][1] = n[0][1]; n[2][2] = n[0][2];
}
for (int k = 0; k < 3; k++) {
vb.push_back(v[k][0]);
vb.push_back(v[k][1]);
vb.push_back(v[k][2]);
vb.push_back(n[k][0]);
vb.push_back(n[k][1]);
vb.push_back(n[k][2]);
// Use normal as color.
float c[3] = {n[k][0], n[k][1], n[k][2]};
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
if (len2 > 1.0e-6f) {
float len = sqrtf(len2);
c[0] /= len;
c[1] /= len;
c[2] /= len;
}
vb.push_back(c[0] * 0.5 + 0.5);
vb.push_back(c[1] * 0.5 + 0.5);
vb.push_back(c[2] * 0.5 + 0.5);
}
}
face_offset += attrib.face_num_verts[v];
}
o.vb = 0;
o.numTriangles = 0;
if (vb.size() > 0) {
glGenBuffers(1, &o.vb);
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0), GL_STATIC_DRAW);
o.numTriangles = vb.size() / 9 / 3;
}
gDrawObjects.push_back(o);
}
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
return true;
}
void reshapeFunc(GLFWwindow* window, int w, int h)
{
(void)window;
// for retinal display.
int fb_w, fb_h;
glfwGetFramebufferSize(window, &fb_w, &fb_h);
glViewport(0, 0, fb_w, fb_h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (float)w / (float)h, 0.01f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
width = w;
height = h;
}
void keyboardFunc(GLFWwindow *window, int key, int scancode, int action, int mods) {
(void)window;
(void)scancode;
(void)mods;
if(action == GLFW_PRESS || action == GLFW_REPEAT){
// Move camera
float mv_x = 0, mv_y = 0, mv_z = 0;
if(key == GLFW_KEY_K) mv_x += 1;
else if(key == GLFW_KEY_J) mv_x += -1;
else if(key == GLFW_KEY_L) mv_y += 1;
else if(key == GLFW_KEY_H) mv_y += -1;
else if(key == GLFW_KEY_P) mv_z += 1;
else if(key == GLFW_KEY_N) mv_z += -1;
//camera.move(mv_x * 0.05, mv_y * 0.05, mv_z * 0.05);
// Close window
if(key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE);
//init_frame = true;
}
}
void clickFunc(GLFWwindow* window, int button, int action, int mods){
(void)window;
(void)mods;
if(button == GLFW_MOUSE_BUTTON_LEFT){
if(action == GLFW_PRESS){
mouseLeftPressed = true;
trackball(prev_quat, 0.0, 0.0, 0.0, 0.0);
} else if(action == GLFW_RELEASE){
mouseLeftPressed = false;
}
}
if(button == GLFW_MOUSE_BUTTON_RIGHT){
if(action == GLFW_PRESS){
mouseRightPressed = true;
} else if(action == GLFW_RELEASE){
mouseRightPressed = false;
}
}
if(button == GLFW_MOUSE_BUTTON_MIDDLE){
if(action == GLFW_PRESS){
mouseMiddlePressed = true;
} else if(action == GLFW_RELEASE){
mouseMiddlePressed = false;
}
}
}
void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y){
(void)window;
float rotScale = 1.0f;
float transScale = 2.0f;
if(mouseLeftPressed){
trackball(prev_quat,
rotScale * (2.0f * prevMouseX - width) / (float)width,
rotScale * (height - 2.0f * prevMouseY) / (float)height,
rotScale * (2.0f * mouse_x - width) / (float)width,
rotScale * (height - 2.0f * mouse_y) / (float)height);
add_quats(prev_quat, curr_quat, curr_quat);
} else if (mouseMiddlePressed) {
eye[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
lookat[0] -= transScale * (mouse_x - prevMouseX) / (float)width;
eye[1] += transScale * (mouse_y - prevMouseY) / (float)height;
lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height;
} else if (mouseRightPressed) {
eye[2] += transScale * (mouse_y - prevMouseY) / (float)height;
lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height;
}
// Update mouse point
prevMouseX = mouse_x;
prevMouseY = mouse_y;
}
void Draw(const std::vector<DrawObject>& drawObjects)
{
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 1.0);
glColor3f(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < drawObjects.size(); i++) {
DrawObject o = drawObjects[i];
if (o.vb < 1) {
continue;
}
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3));
glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float)*6));
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
CheckErrors("drawarrays");
}
// draw wireframe
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
glColor3f(0.0f, 0.0f, 0.4f);
for (size_t i = 0; i < drawObjects.size(); i++) {
DrawObject o = drawObjects[i];
if (o.vb < 1) {
continue;
}
glBindBuffer(GL_ARRAY_BUFFER, o.vb);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 36, (const void*)0);
glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3));
glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles);
CheckErrors("drawarrays");
}
}
static void Init() {
trackball(curr_quat, 0, 0, 0, 0);
eye[0] = 0.0f;
eye[1] = 0.0f;
eye[2] = 3.0f;
lookat[0] = 0.0f;
lookat[1] = 0.0f;
lookat[2] = 0.0f;
up[0] = 0.0f;
up[1] = 1.0f;
up[2] = 0.0f;
}
int main(int argc, char **argv)
{
if (argc < 2) {
std::cout << "view input.obj <num_threads> <benchark_only> <verbose>" << std::endl;
return 0;
}
bool benchmark_only = false;
int num_threads = -1;
bool verbose = false;
if (argc > 2) {
num_threads = atoi(argv[2]);
}
if (argc > 3) {
benchmark_only = (atoi(argv[3]) > 0) ? true : false;
}
if (argc > 4) {
verbose = true;
}
if (benchmark_only) {
tinyobj_opt::attrib_t attrib;
std::vector<tinyobj_opt::shape_t> shapes;
std::vector<tinyobj_opt::material_t> materials;
size_t data_len = 0;
const char* data = get_file_data(&data_len, argv[1]);
if (data == nullptr) {
printf("failed to load file\n");
exit(-1);
return false;
}
if (data_len < 4) {
printf("Empty file\n");
exit(-1);
return false;
}
printf("filesize: %d\n", (int)data_len);
tinyobj_opt::LoadOption option;
option.req_num_threads = num_threads;
option.verbose = true;
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
return ret;
}
Init();
std::cout << "Initialize GLFW..." << std::endl;
if(!glfwInit()){
std::cerr << "Failed to initialize GLFW." << std::endl;
return -1;
}
std::cout << "GLFW OK." << std::endl;
window = glfwCreateWindow(width, height, "Obj viewer", NULL, NULL);
if(window == NULL){
std::cerr << "Failed to open GLFW window. " << std::endl;
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
// Callback
glfwSetWindowSizeCallback(window, reshapeFunc);
glfwSetKeyCallback(window, keyboardFunc);
glfwSetMouseButtonCallback(window, clickFunc);
glfwSetCursorPosCallback(window, motionFunc);
glewExperimental = true;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW." << std::endl;
return -1;
}
reshapeFunc(window, width, height);
float bmin[3], bmax[3];
if (false == LoadObjAndConvert(bmin, bmax, argv[1], num_threads, verbose)) {
printf("failed to load & conv\n");
return -1;
}
float maxExtent = 0.5f * (bmax[0] - bmin[0]);
if (maxExtent < 0.5f * (bmax[1] - bmin[1])) {
maxExtent = 0.5f * (bmax[1] - bmin[1]);
}
if (maxExtent < 0.5f * (bmax[2] - bmin[2])) {
maxExtent = 0.5f * (bmax[2] - bmin[2]);
}
while(glfwWindowShouldClose(window) == GL_FALSE) {
glfwPollEvents();
glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// camera & rotate
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat mat[4][4];
gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0], up[1], up[2]);
build_rotmatrix(mat, curr_quat);
glMultMatrixf(&mat[0][0]);
// Fit to -1, 1
glScalef(1.0f / maxExtent, 1.0f / maxExtent, 1.0f / maxExtent);
// Centerize object.
glTranslatef(-0.5*(bmax[0] + bmin[0]), -0.5*(bmax[1] + bmin[1]), -0.5*(bmax[2] + bmin[2]));
Draw(gDrawObjects);
glfwSwapBuffers(window);
}
glfwTerminate();
}

BIN
fuzzer/afl.tar.gz Normal file

Binary file not shown.

20
fuzzer/runner.py Normal file
View File

@@ -0,0 +1,20 @@
import os, sys
import glob
import subprocess
def main():
for g in glob.glob("../tests/afl/id*"):
print(g)
cmd = ["../a.out", g]
proc = subprocess.Popen(cmd)
try:
outs, errs = proc.communicate(timeout=15)
print(outs)
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
main()

BIN
images/sanmugel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

View File

@@ -5,8 +5,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := tinyobjloader LOCAL_MODULE := tinyobjloader
LOCAL_SRC_FILES := ../tiny_obj_loader.cc ../test.cc LOCAL_SRC_FILES := ../tiny_obj_loader.cc
LOCAL_C_INCLUDES := ../ LOCAL_C_INCLUDES := ../
include $(BUILD_EXECUTABLE) include $(BUILD_STATIC_LIBRARY)

435
loader_example.cc Normal file
View File

@@ -0,0 +1,435 @@
//
// g++ loader_example.cc
//
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#ifdef _WIN32
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
#include <mmsystem.h>
#ifdef __cplusplus
}
#endif
#pragma comment(lib, "winmm.lib")
#else
#if defined(__unix__) || defined(__APPLE__)
#include <sys/time.h>
#else
#include <ctime>
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#endif
class timerutil {
public:
#ifdef _WIN32
typedef DWORD time_t;
timerutil() { ::timeBeginPeriod(1); }
~timerutil() { ::timeEndPeriod(1); }
void start() { t_[0] = ::timeGetTime(); }
void end() { t_[1] = ::timeGetTime(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / 1000); }
time_t msec() { return (time_t)((t_[1] - t_[0])); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000); }
time_t current() { return ::timeGetTime(); }
#else
#if defined(__unix__) || defined(__APPLE__)
typedef unsigned long int time_t;
void start() { gettimeofday(tv + 0, &tz); }
void end() { gettimeofday(tv + 1, &tz); }
time_t sec() { return static_cast<time_t>(tv[1].tv_sec - tv[0].tv_sec); }
time_t msec() {
return this->sec() * 1000 +
static_cast<time_t>((tv[1].tv_usec - tv[0].tv_usec) / 1000);
}
time_t usec() {
return this->sec() * 1000000 +
static_cast<time_t>(tv[1].tv_usec - tv[0].tv_usec);
}
time_t current() {
struct timeval t;
gettimeofday(&t, NULL);
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
}
#else // C timer
// using namespace std;
typedef clock_t time_t;
void start() { t_[0] = clock(); }
void end() { t_[1] = clock(); }
time_t sec() { return (time_t)((t_[1] - t_[0]) / CLOCKS_PER_SEC); }
time_t msec() { return (time_t)((t_[1] - t_[0]) * 1000 / CLOCKS_PER_SEC); }
time_t usec() { return (time_t)((t_[1] - t_[0]) * 1000000 / CLOCKS_PER_SEC); }
time_t current() { return (time_t)clock(); }
#endif
#endif
private:
#ifdef _WIN32
DWORD t_[2];
#else
#if defined(__unix__) || defined(__APPLE__)
struct timeval tv[2];
struct timezone tz;
#else
time_t t_[2];
#endif
#endif
};
static void PrintInfo(const tinyobj::attrib_t& attrib,
const std::vector<tinyobj::shape_t>& shapes,
const std::vector<tinyobj::material_t>& materials) {
std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
<< std::endl;
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.vertices[3 * v + 0]),
static_cast<const double>(attrib.vertices[3 * v + 1]),
static_cast<const double>(attrib.vertices[3 * v + 2]));
}
for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.normals[3 * v + 0]),
static_cast<const double>(attrib.normals[3 * v + 1]),
static_cast<const double>(attrib.normals[3 * v + 2]));
}
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.texcoords[2 * v + 0]),
static_cast<const double>(attrib.texcoords[2 * v + 1]));
}
// For each shape
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", static_cast<long>(i),
shapes[i].name.c_str());
printf("Size of shape[%ld].mesh.indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.indices.size()));
printf("Size of shape[%ld].path.indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].path.indices.size()));
size_t index_offset = 0;
assert(shapes[i].mesh.num_face_vertices.size() ==
shapes[i].mesh.material_ids.size());
assert(shapes[i].mesh.num_face_vertices.size() ==
shapes[i].mesh.smoothing_group_ids.size());
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
// For each face
for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) {
size_t fnum = shapes[i].mesh.num_face_vertices[f];
printf(" face[%ld].fnum = %ld\n", static_cast<long>(f),
static_cast<unsigned long>(fnum));
// For each vertex in the face
for (size_t v = 0; v < fnum; v++) {
tinyobj::index_t idx = shapes[i].mesh.indices[index_offset + v];
printf(" face[%ld].v[%ld].idx = %d/%d/%d\n", static_cast<long>(f),
static_cast<long>(v), idx.vertex_index, idx.normal_index,
idx.texcoord_index);
}
printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
shapes[i].mesh.material_ids[f]);
printf(" face[%ld].smoothing_group_id = %d\n", static_cast<long>(f),
shapes[i].mesh.smoothing_group_ids[f]);
index_offset += fnum;
}
printf("shape[%ld].num_tags: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.tags.size()));
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
printf(" tag[%ld] = %s ", static_cast<long>(t),
shapes[i].mesh.tags[t].name.c_str());
printf(" ints: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j) {
printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
if (j < (shapes[i].mesh.tags[t].intValues.size() - 1)) {
printf(", ");
}
}
printf("]");
printf(" floats: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j) {
printf("%f", static_cast<const double>(
shapes[i].mesh.tags[t].floatValues[j]));
if (j < (shapes[i].mesh.tags[t].floatValues.size() - 1)) {
printf(", ");
}
}
printf("]");
printf(" strings: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j) {
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
if (j < (shapes[i].mesh.tags[t].stringValues.size() - 1)) {
printf(", ");
}
}
printf("]");
printf("\n");
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", static_cast<long>(i),
materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].ambient[0]),
static_cast<const double>(materials[i].ambient[1]),
static_cast<const double>(materials[i].ambient[2]));
printf(" material.Kd = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].diffuse[0]),
static_cast<const double>(materials[i].diffuse[1]),
static_cast<const double>(materials[i].diffuse[2]));
printf(" material.Ks = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].specular[0]),
static_cast<const double>(materials[i].specular[1]),
static_cast<const double>(materials[i].specular[2]));
printf(" material.Tr = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].transmittance[0]),
static_cast<const double>(materials[i].transmittance[1]),
static_cast<const double>(materials[i].transmittance[2]));
printf(" material.Ke = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].emission[0]),
static_cast<const double>(materials[i].emission[1]),
static_cast<const double>(materials[i].emission[2]));
printf(" material.Ns = %f\n",
static_cast<const double>(materials[i].shininess));
printf(" material.Ni = %f\n", static_cast<const double>(materials[i].ior));
printf(" material.dissolve = %f\n",
static_cast<const double>(materials[i].dissolve));
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n",
materials[i].specular_highlight_texname.c_str());
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
printf(" bump_multiplier = %f\n", static_cast<const double>(materials[i].bump_texopt.bump_multiplier));
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
printf(" <<PBR>>\n");
printf(" material.Pr = %f\n", static_cast<const double>(materials[i].roughness));
printf(" material.Pm = %f\n", static_cast<const double>(materials[i].metallic));
printf(" material.Ps = %f\n", static_cast<const double>(materials[i].sheen));
printf(" material.Pc = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
printf(" material.Pcr = %f\n", static_cast<const double>(materials[i].clearcoat_thickness));
printf(" material.aniso = %f\n", static_cast<const double>(materials[i].anisotropy));
printf(" material.anisor = %f\n", static_cast<const double>(materials[i].anisotropy_rotation));
printf(" material.map_Ke = %s\n", materials[i].emissive_texname.c_str());
printf(" material.map_Pr = %s\n", materials[i].roughness_texname.c_str());
printf(" material.map_Pm = %s\n", materials[i].metallic_texname.c_str());
printf(" material.map_Ps = %s\n", materials[i].sheen_texname.c_str());
printf(" material.norm = %s\n", materials[i].normal_texname.c_str());
std::map<std::string, std::string>::const_iterator it(
materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(
materials[i].unknown_parameter.end());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
}
static bool TestLoadObj(const char* filename, const char* basepath = NULL,
bool triangulate = true) {
std::cout << "Loading " << filename << std::endl;
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
timerutil t;
t.start();
std::string warn;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename,
basepath, triangulate);
t.end();
printf("Parsing time: %lu [msecs]\n", t.msec());
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "ERR: " << err << std::endl;
}
if (!ret) {
printf("Failed to load/parse .obj.\n");
return false;
}
PrintInfo(attrib, shapes, materials);
return true;
}
static bool TestStreamLoadObj() {
std::cout << "Stream Loading " << std::endl;
std::stringstream objStream;
objStream << "mtllib cube.mtl\n"
"\n"
"v 0.000000 2.000000 2.000000\n"
"v 0.000000 0.000000 2.000000\n"
"v 2.000000 0.000000 2.000000\n"
"v 2.000000 2.000000 2.000000\n"
"v 0.000000 2.000000 0.000000\n"
"v 0.000000 0.000000 0.000000\n"
"v 2.000000 0.000000 0.000000\n"
"v 2.000000 2.000000 0.000000\n"
"# 8 vertices\n"
"\n"
"g front cube\n"
"usemtl white\n"
"f 1 2 3 4\n"
"g back cube\n"
"# expects white material\n"
"f 8 7 6 5\n"
"g right cube\n"
"usemtl red\n"
"f 4 3 7 8\n"
"g top cube\n"
"usemtl white\n"
"f 5 1 4 8\n"
"g left cube\n"
"usemtl green\n"
"f 5 6 2 1\n"
"g bottom cube\n"
"usemtl white\n"
"f 2 6 7 3\n"
"# 6 elements";
std::string matStream(
"newmtl white\n"
"Ka 0 0 0\n"
"Kd 1 1 1\n"
"Ks 0 0 0\n"
"\n"
"newmtl red\n"
"Ka 0 0 0\n"
"Kd 1 0 0\n"
"Ks 0 0 0\n"
"\n"
"newmtl green\n"
"Ka 0 0 0\n"
"Kd 0 1 0\n"
"Ks 0 0 0\n"
"\n"
"newmtl blue\n"
"Ka 0 0 0\n"
"Kd 0 0 1\n"
"Ks 0 0 0\n"
"\n"
"newmtl light\n"
"Ka 20 20 20\n"
"Kd 1 1 1\n"
"Ks 0 0 0");
using namespace tinyobj;
class MaterialStringStreamReader : public MaterialReader {
public:
MaterialStringStreamReader(const std::string& matSStream)
: m_matSStream(matSStream) {}
virtual ~MaterialStringStreamReader() {}
virtual bool operator()(const std::string& matId,
std::vector<material_t>* materials,
std::map<std::string, int>* matMap,
std::string* warn,
std::string* err) {
(void)err;
(void)matId;
LoadMtl(matMap, materials, &m_matSStream, warn, err);
return true;
}
private:
std::stringstream m_matSStream;
};
MaterialStringStreamReader matSSReader(matStream);
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, &objStream,
&matSSReader);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
return false;
}
PrintInfo(attrib, shapes, materials);
return true;
}
int main(int argc, char** argv) {
if (argc > 1) {
const char* basepath = "models/";
if (argc > 2) {
basepath = argv[2];
}
assert(true == TestLoadObj(argv[1], basepath));
} else {
// assert(true == TestLoadObj("cornell_box.obj"));
// assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj());
assert(true ==
TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
}
return 0;
}

View File

@@ -0,0 +1,9 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3
map_Kd -colorspace sRGB -o 0.1 diffuse.jpg
map_Ks -s 0.1 0.2 specular.jpg
map_bump -colorspace linear -bm 3 bumpmap.jpg

View File

@@ -0,0 +1,7 @@
mtllib colorspace-issue-184.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

31
models/cube-vertexcol.obj Normal file
View File

@@ -0,0 +1,31 @@
mtllib cube.mtl
v 0.000000 2.000000 2.000000 0 0 0
v 0.000000 0.000000 2.000000 0 0 1
v 2.000000 0.000000 2.000000 0 1 0
v 2.000000 2.000000 2.000000 0 1 1
v 0.000000 2.000000 0.000000 1 0 0
v 0.000000 0.000000 0.000000 1 0 1
v 2.000000 0.000000 0.000000 1 1 0
v 2.000000 2.000000 0.000000 1 1 1
# 8 vertices
g front cube
usemtl white
f 1 2 3 4
g back cube
# expects white material
f 8 7 6 5
g right cube
usemtl red
f 4 3 7 8
g top cube
usemtl white
f 5 1 4 8
g left cube
usemtl green
f 5 6 2 1
g bottom cube
usemtl white
f 2 6 7 3
# 6 elements

View File

@@ -13,7 +13,8 @@ v 2.000000 2.000000 0.000000
g front cube g front cube
usemtl white usemtl white
f 1 2 3 4 f 1 2 3 4
g back cube # two white spaces between 'back' and 'cube'
g back cube
# expects white material # expects white material
f 8 7 6 5 f 8 7 6 5
g right cube g right cube

View File

@@ -0,0 +1,24 @@
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
newmtl red
Ka 0 0 0
Kd 1 0 0
Ks 0 0 0
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue
Ka 0 0 0
Kd 0 0 1
Ks 0 0 0
newmtl light
Ka 20 20 20
Kd 1 1 1
Ks 0 0 0

View File

@@ -0,0 +1,18 @@
mtllib invalid-face-definition.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g front cube
usemtl white
f 1
g back cube
# expects white material
f 8 7

23
models/issue-138.mtl Normal file
View File

@@ -0,0 +1,23 @@
newmtl test1
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.5 0.2 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
newmtl test2
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.2 0.5 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000

51
models/issue-138.obj Normal file
View File

@@ -0,0 +1,51 @@
# cube.obj
#
mtllib issue-138.mtl
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
usemtl test1
g test1
s 1
f 1/1/1 2/2/1 3/3/1
f 3/3/1 2/2/1 4/4/1
usemtl test2
g test2
s 2
f 3/1/2 4/2/2 5/3/2
f 5/3/2 4/2/2 6/4/2
s 3
f 5/4/3 6/3/3 7/2/3
f 7/2/3 6/3/3 8/1/3
s 4
f 7/1/4 8/2/4 1/3/4
f 1/3/4 8/2/4 2/4/4
s 5
f 2/1/5 8/2/5 4/3/5
f 4/3/5 8/2/5 6/4/5
s 6
f 7/1/6 1/2/6 5/3/6
f 5/3/6 1/2/6 3/4/6

View File

@@ -0,0 +1,2 @@
newmtl main
Kd 1 1 1

View File

@@ -0,0 +1,17 @@
mtllib issue-140-zero-face-idx.mtl
v -0.5 -0.5 0
v 0.5 -0.5 0
v 0.5 0.5 0
v -0.5 0.5 0
vt 0 0 0
vt 1 0 0
vt 1 1 0
vt 0 1 0
vn 0 0 -1
usemtl main
f 0/0/0 1/1/0 3/3/0
f 1/1/0 3/3/0 2/2/0

View File

@@ -0,0 +1,37 @@
o cube
mtllib cube.mtl
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
g cube
usemtl cube
s 1
f 1/1 2/2 3/3
f 3/3 2/2 4/4
s 2
f 3/1 4/2 5/3
f 5/3 4/2 6/4
s 3
f 5/4 6/3 7/2
f 7/2 6/3 8/1
s 4
f 7/1 8/2 1/3
f 1/3 8/2 2/4
s 5
f 2/1 8/2 4/3
f 4/3 8/2 6/4
s 6
f 7/1 1/2 5/3
f 5 1 3

View File

@@ -0,0 +1,23 @@
newmtl test1
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.5 0.2 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
newmtl test2
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.2 0.5 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000

View File

@@ -0,0 +1,51 @@
# cube.obj
#
mtllib issue-162-smoothing-group.mtl
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
usemtl test1
g test1
s 1
f 1/1/1 2/2/1 3/3/1
f 3/3/1 2/2/1 4/4/1
usemtl test2
g test2
s off
f 3/1/2 4/2/2 5/3/2
f 5/3/2 4/2/2 6/4/2
s 3
f 5/4/3 6/3/3 7/2/3
f 7/2/3 6/3/3 8/1/3
s 4
f 7/1/4 8/2/4 1/3/4
f 1/3/4 8/2/4 2/4/4
s 0
f 2/1/5 8/2/5 4/3/5
f 4/3/5 8/2/5 6/4/5
s 6
f 7/1/6 1/2/6 5/3/6
f 5/3/6 1/2/6 3/4/6

6
models/issue-92.mtl Normal file
View File

@@ -0,0 +1,6 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
map_Kd tmp.png

7
models/issue-92.obj Normal file
View File

@@ -0,0 +1,7 @@
mtllib issue-92.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

5
models/issue-95-2.mtl Normal file
View File

@@ -0,0 +1,5 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Tf 0.1 0.2 0.3

7
models/issue-95-2.obj Normal file
View File

@@ -0,0 +1,7 @@
mtllib issue-95-2.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

5
models/issue-95.mtl Normal file
View File

@@ -0,0 +1,5 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3

7
models/issue-95.obj Normal file
View File

@@ -0,0 +1,7 @@
mtllib issue-95.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

16
models/line-prim.obj Normal file
View File

@@ -0,0 +1,16 @@
mtllib cube.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g g0
usemtl white
l 1 2 3 4
l 5 6 7

10
models/map-bump.mtl Normal file
View File

@@ -0,0 +1,10 @@
newmtl Material.001
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
map_Bump bump.jpg
newmtl Material.003
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0

817
models/map-bump.obj Normal file
View File

@@ -0,0 +1,817 @@
# https://github.com/syoyo/tinyobjloader/issues/68
# Blender v2.73 (sub 0) OBJ File: 'enemy.blend'
# www.blender.org
mtllib map-bump.mtl
o Cube
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
v 1.620345 1.000000 -5.815706
v 1.864152 1.000000 -6.334323
v 0.575869 -0.129842 5.896143
v 5.440438 -1.462153 -5.818601
v 4.896782 -1.462153 -2.744413
v 1.000825 -0.677484 1.899605
v 5.440438 -1.246362 -5.818600
v 1.000825 0.852342 1.899608
v 4.896782 -1.246362 -2.744412
v 1.160660 -0.450871 -2.356325
v 1.704316 -0.450871 -5.430513
v 1.000825 -0.351920 -1.293797
v 1.000825 1.000000 -1.293794
v 1.160660 -0.877888 -2.356326
v 1.704316 -0.877888 -5.430514
v 1.000825 -1.219172 -1.452514
v 1.000825 1.000000 -1.452511
v 1.000825 -0.351920 1.759410
v 1.000825 1.000000 1.759413
v 9.097919 1.221145 -6.212147
v 8.356775 1.221145 -2.021231
v 1.864151 -0.109586 -6.334325
v 0.575869 -0.398073 5.896141
v 9.097919 0.943958 -6.212148
v 8.356775 0.943958 -2.021233
v 1.061916 0.113661 -1.797961
v 1.000825 0.161258 1.899606
v 1.000825 0.324040 -1.293795
v 1.803060 0.113661 -5.988876
v 1.000825 -0.109586 -1.452513
v 1.061916 0.776753 -1.797960
v 1.803061 0.776753 -5.988875
v 1.000825 0.324040 1.759412
v 0.000825 -1.219172 -5.532512
v 0.000825 -0.666304 5.896139
v 0.000826 1.000000 -6.334325
v 0.000825 -0.129842 5.896140
v 0.000825 0.852342 1.899606
v 0.000825 -0.677484 1.899604
v 0.000825 -0.351920 -1.293797
v 0.000825 1.000000 -1.293796
v 0.000825 1.000000 -1.452513
v 0.000825 -1.219172 -1.452515
v 0.000825 -0.351920 1.759409
v 0.000825 1.000000 1.759411
v 0.000826 -0.109586 -6.334326
v 0.000825 -0.398073 5.896140
v 0.152918 1.000000 -5.815708
v 0.152917 1.000000 -1.971130
v 0.940448 1.168419 -1.971128
v 1.620345 1.168419 -5.815706
v 0.152918 1.168419 -5.815708
v 0.152917 1.168419 -1.971130
v 0.921118 1.091883 -1.050430
v 0.921118 1.091883 1.516050
v 0.080533 1.091883 -1.050432
v 0.080533 1.091883 1.516048
v 0.613003 -0.553430 5.546911
v 0.963691 -0.559956 2.248834
v 0.613003 -0.396857 5.546912
v 0.963691 -0.070362 2.248835
v 1.499370 -0.994317 3.966028
v 1.850058 -0.997914 0.667950
v 1.499370 -0.908021 3.966029
v 1.850058 -0.728071 0.667951
v 1.601022 0.760960 -6.334324
v 1.601021 0.129454 -6.334325
v 0.263955 0.760960 -6.334325
v 0.263955 0.129454 -6.334325
v 1.334809 0.760960 -7.515329
v 1.334809 0.129455 -7.515330
v 0.530168 0.760960 -7.515330
v 0.530168 0.129455 -7.515330
v 1.192720 0.649445 -7.515329
v 1.192720 0.240971 -7.515330
v 0.672258 0.649445 -7.515330
v 0.672258 0.240971 -7.515330
v 1.192719 0.649444 -6.524630
v 1.192719 0.240970 -6.524631
v 0.672257 0.649444 -6.524631
v 0.672257 0.240970 -6.524631
v 3.851026 0.431116 -1.883326
v 3.851026 0.946662 -1.883325
v 4.592170 0.946662 -6.074241
v 4.592169 0.431116 -6.074242
v 4.995714 0.561404 -1.918362
v 4.995714 1.016394 -1.918360
v 5.736857 1.016394 -6.109276
v 5.736857 0.561404 -6.109277
v 3.975454 0.471731 -2.162156
v 3.975454 0.919244 -2.162155
v 4.618796 0.919244 -5.800034
v 4.618795 0.471730 -5.800035
v 4.969088 0.584825 -2.192568
v 4.969088 0.979775 -2.192567
v 5.612430 0.979775 -5.830446
v 5.612429 0.584825 -5.830447
v 0.864214 -0.673890 3.184381
v 0.864213 0.489129 3.184384
v 0.864213 -0.018552 3.184383
v 0.000825 0.489129 3.184382
v 0.000825 -0.673890 3.184381
v 0.850955 -0.557858 3.309075
v 0.850955 -0.175321 3.309076
v 1.737321 -0.996758 1.728192
v 1.737321 -0.785920 1.728193
v -1.864151 -1.219172 -5.532511
v -0.575869 -0.666304 5.896140
v -0.940448 1.000000 -1.971128
v -1.620345 1.000000 -5.815706
v -1.864152 1.000000 -6.334323
v -0.575869 -0.129842 5.896143
v -5.440438 -1.462153 -5.818601
v -4.896782 -1.462153 -2.744413
v -1.000825 -0.677484 1.899605
v -5.440438 -1.246362 -5.818600
v -1.000825 0.852342 1.899608
v -4.896782 -1.246362 -2.744412
v -1.160660 -0.450871 -2.356325
v -1.704316 -0.450871 -5.430513
v -1.000825 -0.351920 -1.293797
v -1.000825 1.000000 -1.293794
v -1.160660 -0.877888 -2.356326
v -1.704316 -0.877888 -5.430514
v -1.000825 -1.219172 -1.452514
v -1.000825 1.000000 -1.452511
v -1.000825 -0.351920 1.759410
v -1.000825 1.000000 1.759413
v -9.097919 1.221145 -6.212147
v -8.356775 1.221145 -2.021231
v -1.864151 -0.109586 -6.334325
v -0.575869 -0.398073 5.896141
v -9.097919 0.943958 -6.212148
v -8.356775 0.943958 -2.021233
v -1.061916 0.113661 -1.797961
v -1.000825 0.161258 1.899606
v -1.000825 0.324040 -1.293795
v -1.803060 0.113661 -5.988876
v -1.000825 -0.109586 -1.452513
v -1.061916 0.776753 -1.797960
v -1.803061 0.776753 -5.988875
v -1.000825 0.324040 1.759412
v -0.000825 -1.219172 -5.532512
v -0.000825 -0.666304 5.896139
v -0.000826 1.000000 -6.334325
v -0.000825 -0.129842 5.896140
v -0.000825 0.852342 1.899606
v -0.000825 -0.677484 1.899604
v -0.000825 -0.351920 -1.293797
v -0.000825 1.000000 -1.293796
v -0.000825 1.000000 -1.452513
v -0.000825 -1.219172 -1.452515
v -0.000825 -0.351920 1.759409
v -0.000825 1.000000 1.759411
v -0.000826 -0.109586 -6.334326
v -0.000825 -0.398073 5.896140
v -0.152918 1.000000 -5.815708
v -0.152917 1.000000 -1.971130
v -0.940448 1.168419 -1.971128
v -1.620345 1.168419 -5.815706
v -0.152918 1.168419 -5.815708
v -0.152917 1.168419 -1.971130
v -0.921118 1.091883 -1.050430
v -0.921118 1.091883 1.516050
v -0.080533 1.091883 -1.050432
v -0.080533 1.091883 1.516048
v -0.613003 -0.553430 5.546911
v -0.963691 -0.559956 2.248834
v -0.613003 -0.396857 5.546912
v -0.963691 -0.070362 2.248835
v -1.499370 -0.994317 3.966028
v -1.850058 -0.997914 0.667950
v -1.499370 -0.908021 3.966029
v -1.850058 -0.728071 0.667951
v -1.601022 0.760960 -6.334324
v -1.601021 0.129454 -6.334325
v -0.263955 0.760960 -6.334325
v -0.263955 0.129454 -6.334325
v -1.334809 0.760960 -7.515329
v -1.334809 0.129455 -7.515330
v -0.530168 0.760960 -7.515330
v -0.530168 0.129455 -7.515330
v -1.192720 0.649445 -7.515329
v -1.192720 0.240971 -7.515330
v -0.672258 0.649445 -7.515330
v -0.672258 0.240971 -7.515330
v -1.192719 0.649444 -6.524630
v -1.192719 0.240970 -6.524631
v -0.672257 0.649444 -6.524631
v -0.672257 0.240970 -6.524631
v -3.851026 0.431116 -1.883326
v -3.851026 0.946662 -1.883325
v -4.592170 0.946662 -6.074241
v -4.592169 0.431116 -6.074242
v -4.995714 0.561404 -1.918362
v -4.995714 1.016394 -1.918360
v -5.736857 1.016394 -6.109276
v -5.736857 0.561404 -6.109277
v -3.975454 0.471731 -2.162156
v -3.975454 0.919244 -2.162155
v -4.618796 0.919244 -5.800034
v -4.618795 0.471730 -5.800035
v -4.969088 0.584825 -2.192568
v -4.969088 0.979775 -2.192567
v -5.612430 0.979775 -5.830446
v -5.612429 0.584825 -5.830447
v -0.864214 -0.673890 3.184381
v -0.864213 0.489129 3.184384
v -0.864213 -0.018552 3.184383
v -0.000825 0.489129 3.184382
v -0.000825 -0.673890 3.184381
v -0.850955 -0.557858 3.309075
v -0.850955 -0.175321 3.309076
v -1.737321 -0.996758 1.728192
v -1.737321 -0.785920 1.728193
vt 0.135351 -0.558072
vt 0.003035 -0.363507
vt 0.092282 -0.976844
vt -0.081322 0.947351
vt 0.100058 1.958891
vt 0.050091 1.852185
vt -0.092752 1.055565
vt -0.251711 1.059474
vt 0.075587 0.041384
vt -0.086008 0.279003
vt -0.086212 0.249830
vt -0.276044 1.968137
vt -0.246101 1.859467
vt 0.009828 1.911388
vt -0.133014 1.114769
vt 0.413322 1.261595
vt 0.299103 0.624605
vt 1.243955 0.407183
vt 0.515404 1.111487
vt 1.358173 1.044173
vt -0.081553 0.914324
vt 0.080042 0.676706
vt 0.401185 0.474498
vt 1.295541 0.331328
vt 0.365315 1.568841
vt 0.299111 1.575740
vt 0.143401 0.707357
vt 0.629403 1.011947
vt 0.449192 0.167251
vt 1.409760 0.968317
vt 0.986264 1.738667
vt 1.573373 1.877873
vt 1.417663 1.009490
vt 0.237182 -0.196235
vt 0.721785 1.030226
vt 0.830554 0.870285
vt 0.877494 1.898608
vt 1.351399 1.106930
vt 0.183935 0.557301
vt 1.507109 1.975312
vt 0.241636 0.439088
vt 0.114297 -0.045011
vt 0.140593 1.808834
vt -0.015118 0.940452
vt 0.156405 -1.071134
vt 0.164119 -0.998223
vt 0.040336 -1.068281
vt 0.104459 -1.162571
vt -0.165787 1.882802
vt -0.014821 1.660811
vt -0.287852 0.283965
vt -0.293374 0.366508
vt -0.289630 0.900550
vt 0.035337 -0.191272
vt 0.247348 0.172213
vt 0.253300 1.021193
vt -0.283166 0.952313
vt -0.283398 0.919286
vt 0.039792 0.444050
vt 0.314806 -0.339851
vt 0.112962 -0.334889
vt -0.288056 0.254793
vt -0.023788 -0.973990
vt -0.155922 -0.359599
vt 0.220528 -1.165425
vt 0.108710 -0.748730
vt -0.286364 1.918670
vt -0.291973 1.118678
vt -0.119962 0.896379
vt -0.123707 0.362337
vt 0.162891 -0.598569
vt 0.467532 -0.853353
vt 0.201549 -1.053262
vt 0.161663 -0.198915
vt 0.267667 -0.752638
vt 0.278705 -0.371021
vt 0.526390 -0.542053
vt 0.483821 -0.479457
vt 0.488162 -0.883689
vt 0.500110 -0.105561
vt 0.564618 -0.200418
vt -0.110331 2.127229
vt 0.040636 1.905238
vt -0.010786 1.578087
vt 0.104092 1.876168
vt 0.255058 1.654176
vt -0.054992 2.087323
vt 0.203048 1.901245
vt 0.052081 2.123235
vt 0.042658 1.943733
vt -0.056437 1.881175
vt 0.147710 1.941151
vt 0.050060 2.084741
vt 0.146264 1.735002
vt 0.041212 1.737584
vt 0.048615 1.878591
vt 0.663065 1.872485
vt 0.786311 1.691257
vt 0.507355 1.004102
vt 0.630601 0.822874
vt 0.955144 1.689498
vt 0.860727 1.828333
vt 0.725565 1.074543
vt 0.819981 0.935708
vt 0.674594 1.805657
vt 0.539432 1.051867
vt 0.646413 0.894554
vt 0.781576 1.648344
vt 0.240127 -0.712141
vn 0.994400 0.000000 0.105700
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.984700 0.000000 0.174100
vn 0.211800 0.976600 0.037500
vn -0.103300 0.000000 -0.994600
vn 0.103300 -0.000000 0.994600
vn 0.911400 0.378700 0.161200
vn -0.157300 -0.987200 -0.027800
vn 0.113700 -0.993300 0.020100
vn 0.030600 -0.000000 0.999500
vn -0.061100 0.998100 -0.010800
vn -0.030600 0.000000 -0.999500
vn -0.000000 -0.000000 1.000000
vn 0.000000 0.000000 -1.000000
vn -0.755400 0.655300 0.000000
vn 0.000000 -1.000000 0.000000
vn -0.000000 -0.180000 0.983700
vn 0.000000 -0.395500 -0.918500
vn -0.000000 0.688500 0.725200
vn 0.000000 -0.585700 -0.810500
vn -0.000000 0.974900 0.222500
vn -0.000000 -1.000000 0.002800
vn -1.000000 0.000000 -0.000000
vn -0.000000 0.935500 0.353200
vn 0.755400 0.655300 0.000000
vn 0.000000 0.935500 -0.353200
vn 0.673800 0.724900 0.143400
vn 0.872300 -0.000000 0.489100
vn -0.872300 0.000000 -0.489100
vn -0.518300 -0.853500 -0.054200
vn -0.975500 0.000000 -0.219900
vn 0.975500 0.000000 -0.219900
vn -0.913200 0.000000 -0.407500
vn -0.436900 0.896200 -0.077300
vn -0.995300 -0.000000 0.096600
vn -0.297300 -0.953400 -0.052600
vn 0.473900 -0.876600 0.083800
vn 0.913200 0.000000 0.407500
vn 0.342200 0.937700 0.060500
vn 0.995300 -0.000000 -0.096600
vn -0.519200 -0.853000 -0.054300
vn 0.722400 0.676400 0.143800
vn -0.994400 0.000000 0.105700
vn -0.984700 0.000000 0.174100
vn -0.211800 0.976600 0.037500
vn 0.103300 0.000000 -0.994600
vn -0.103300 -0.000000 0.994600
vn -0.911400 0.378700 0.161200
vn 0.157300 -0.987200 -0.027800
vn -0.113700 -0.993300 0.020100
vn -0.030600 -0.000000 0.999500
vn 0.061100 0.998100 -0.010800
vn 0.030600 0.000000 -0.999500
vn -0.691900 0.713200 0.112500
vn -0.872300 -0.000000 0.489100
vn 0.872300 0.000000 -0.489100
vn 0.518300 -0.853500 -0.054200
vn 0.913200 0.000000 -0.407500
vn 0.436900 0.896200 -0.077300
vn 0.995300 0.000000 0.096600
vn 0.297300 -0.953300 -0.052600
vn -0.473900 -0.876600 0.083800
vn -0.913200 -0.000000 0.407500
vn -0.342200 0.937700 0.060500
vn -0.995300 -0.000000 -0.096600
vn 0.519200 -0.853000 -0.054300
vn -0.714800 0.690100 0.113700
vn 0.974400 0.089700 0.206200
vn 0.870400 0.288400 0.399100
vn 0.691900 0.713200 0.112500
vn -0.518000 -0.853700 -0.053400
vn -0.519700 -0.852700 -0.053600
vn 0.714800 0.690100 0.113700
vn -0.974400 0.089700 0.206200
vn -0.870400 0.288400 0.399100
vn -0.673800 0.724900 0.143400
vn 0.518000 -0.853700 -0.053400
vn 0.297300 -0.953400 -0.052600
vn 0.519700 -0.852700 -0.053600
vn -0.722400 0.676400 0.143800
vn -0.000000 0.962300 0.272000
usemtl Material.001
s off
f 103/1/1 102/2/1 6/3/1
f 20/4/2 5/5/2 4/6/2
f 20/4/2 3/7/2 52/8/2
f 36/9/3 22/10/3 11/11/3
f 39/12/2 51/13/2 4/6/2
f 4/6/4 54/14/4 53/15/4
f 14/16/5 13/17/5 12/18/5
f 18/19/6 14/16/6 10/20/6
f 20/4/3 16/21/3 31/22/3
f 17/23/7 8/24/7 12/18/7
f 25/25/4 32/26/4 29/27/4
f 10/20/4 12/18/4 8/24/4
f 1/28/8 18/19/8 17/23/8
f 19/29/4 17/23/4 13/17/4
f 25/25/4 14/16/4 18/19/4
f 18/19/9 7/30/9 8/24/9
f 92/31/10 27/32/10 28/33/10
f 16/21/3 22/10/3 36/9/3
f 31/22/3 36/9/3 21/34/3
f 90/35/11 89/36/11 28/33/11
f 91/37/12 90/35/12 24/38/12
f 33/39/4 13/17/4 14/16/4
f 23/40/4 24/38/4 28/33/4
f 33/39/3 31/22/3 15/41/3
f 21/34/3 36/9/3 30/42/3
f 5/5/4 35/43/4 32/26/4
f 5/5/4 20/4/4 34/44/4
f 33/39/4 29/27/4 34/44/4
f 91/37/13 23/40/13 27/32/13
f 103/1/1 26/45/1 63/46/1
f 26/45/14 50/47/14 38/48/14
f 39/12/15 71/49/15 72/50/15
f 48/51/16 60/52/16 59/53/16
f 15/41/17 21/34/17 47/54/17
f 19/29/17 46/55/17 37/56/17
f 39/12/2 45/57/2 52/8/2
f 20/4/2 45/57/2 44/58/2
f 19/29/18 15/41/18 43/59/18
f 9/60/19 42/61/19 47/54/19
f 22/10/20 48/51/20 41/62/20
f 25/25/21 1/28/21 37/56/21
f 6/3/14 40/63/14 50/47/14
f 104/64/22 40/63/22 6/3/22
f 2/65/23 38/48/23 105/66/23
f 55/67/2 56/68/2 53/15/2
f 3/7/14 53/15/14 56/68/14
f 51/13/15 55/67/15 54/14/15
f 52/8/24 56/68/24 55/67/24
f 57/69/2 59/53/2 60/52/2
f 48/51/25 22/10/25 58/70/25
f 16/21/26 57/69/26 58/70/26
f 16/21/27 44/58/27 59/53/27
f 107/71/28 63/46/28 67/72/28
f 26/45/1 2/65/1 61/73/1
f 9/60/1 30/42/1 64/74/1
f 101/75/1 9/60/1 62/76/1
f 108/77/1 109/78/1 67/72/1
f 61/73/29 65/79/29 67/72/29
f 62/76/30 64/74/30 68/80/30
f 62/76/31 66/81/31 108/77/31
f 71/49/32 75/82/32 76/83/32
f 25/25/15 49/84/15 72/50/15
f 5/5/15 69/85/15 71/49/15
f 25/25/15 70/86/15 69/85/15
f 76/83/15 75/82/15 79/87/15
f 72/50/17 76/83/17 74/88/17
f 71/49/2 69/85/2 73/89/2
f 70/86/33 74/88/33 73/89/33
f 80/90/3 79/87/3 83/91/3
f 76/83/15 80/90/15 78/92/15
f 75/82/15 73/89/15 77/93/15
f 74/88/15 78/92/15 77/93/15
f 82/94/15 84/95/15 83/91/15
f 80/90/2 84/95/2 82/94/2
f 77/93/17 81/96/17 83/91/17
f 77/93/24 78/92/24 82/94/24
f 35/43/13 87/97/13 88/98/13
f 35/43/12 34/44/12 86/99/12
f 34/44/11 29/27/11 85/100/11
f 32/26/10 88/98/10 85/100/10
f 92/31/34 100/101/34 99/102/34
f 90/35/35 91/37/35 99/102/35
f 89/36/36 90/35/36 98/103/36
f 89/36/37 97/104/37 100/101/37
f 95/105/13 99/102/13 100/101/13
f 95/105/12 94/106/12 98/103/12
f 94/106/11 93/107/11 97/104/11
f 96/108/10 100/101/10 97/104/10
f 88/98/38 96/108/38 93/107/38
f 86/99/39 85/100/39 93/107/39
f 87/97/40 86/99/40 94/106/40
f 87/97/41 95/105/41 96/108/41
f 106/109/42 108/77/42 65/79/42
f 66/81/1 68/80/1 109/78/1
f 101/75/1 106/109/1 61/73/1
f 64/74/43 107/71/43 109/78/43
f 101/75/23 105/66/23 42/61/23
f 103/1/1 107/71/1 64/74/1
f 30/42/1 11/11/1 102/2/1
f 212/1/44 135/45/44 115/3/44
f 129/4/2 112/7/2 113/6/2
f 161/8/2 112/7/2 129/4/2
f 145/9/24 139/42/24 120/11/24
f 113/6/2 160/13/2 148/12/2
f 162/15/45 163/14/45 113/6/45
f 123/16/46 119/20/46 121/18/46
f 127/19/47 116/30/47 119/20/47
f 140/22/24 125/21/24 129/4/24
f 121/18/48 117/24/48 126/23/48
f 138/27/45 141/26/45 134/25/45
f 117/24/45 121/18/45 119/20/45
f 126/23/49 127/19/49 110/28/49
f 122/17/45 126/23/45 128/29/45
f 127/19/45 123/16/45 134/25/45
f 117/24/50 116/30/50 127/19/50
f 137/33/51 136/32/51 201/31/51
f 145/9/24 131/10/24 125/21/24
f 130/34/24 145/9/24 140/22/24
f 199/35/52 133/38/52 137/33/52
f 200/37/53 132/40/53 133/38/53
f 123/16/45 122/17/45 142/39/45
f 137/33/45 133/38/45 132/40/45
f 124/41/24 140/22/24 142/39/24
f 130/34/24 118/60/24 139/42/24
f 141/26/45 144/43/45 114/5/45
f 114/5/45 144/43/45 143/44/45
f 143/44/45 138/27/45 142/39/45
f 136/32/54 132/40/54 200/37/54
f 212/1/44 216/71/44 172/46/44
f 147/48/14 159/47/14 135/45/14
f 181/50/15 180/49/15 148/12/15
f 168/53/26 169/52/26 157/51/26
f 124/41/17 152/59/17 156/54/17
f 146/56/17 155/55/17 128/29/17
f 148/12/2 160/13/2 161/8/2
f 129/4/2 125/21/2 153/58/2
f 155/55/18 152/59/18 124/41/18
f 130/34/19 156/54/19 151/61/19
f 131/10/20 120/11/20 150/62/20
f 134/25/21 158/84/21 146/56/21
f 159/47/14 149/63/14 115/3/14
f 115/3/22 149/63/22 213/64/22
f 214/66/23 147/48/23 111/65/23
f 162/15/2 165/68/2 164/67/2
f 165/68/14 162/15/14 112/7/14
f 163/14/15 164/67/15 160/13/15
f 164/67/3 165/68/3 161/8/3
f 166/69/2 167/70/2 169/52/2
f 157/51/25 169/52/25 167/70/25
f 167/70/16 166/69/16 125/21/16
f 125/21/27 166/69/27 168/53/27
f 216/71/55 218/78/55 176/72/55
f 135/45/44 172/46/44 170/73/44
f 118/60/44 171/76/44 173/74/44
f 210/75/44 215/109/44 171/76/44
f 217/77/44 174/79/44 176/72/44
f 176/72/56 174/79/56 170/73/56
f 171/76/57 175/81/57 177/80/57
f 217/77/58 175/81/58 171/76/58
f 185/83/33 184/82/33 180/49/33
f 134/25/15 179/86/15 181/50/15
f 180/49/15 178/85/15 114/5/15
f 178/85/15 179/86/15 134/25/15
f 189/90/15 188/87/15 184/82/15
f 183/88/17 185/83/17 181/50/17
f 180/49/2 184/82/2 182/89/2
f 182/89/32 183/88/32 179/86/32
f 189/90/24 193/95/24 192/91/24
f 187/92/15 189/90/15 185/83/15
f 184/82/15 188/87/15 186/93/15
f 186/93/15 187/92/15 183/88/15
f 192/91/15 193/95/15 191/94/15
f 191/94/2 193/95/2 189/90/2
f 192/91/17 190/96/17 186/93/17
f 186/93/3 190/96/3 191/94/3
f 197/98/54 196/97/54 144/43/54
f 144/43/53 196/97/53 195/99/53
f 143/44/52 195/99/52 194/100/52
f 194/100/51 197/98/51 141/26/51
f 208/102/59 209/101/59 201/31/59
f 199/35/60 207/103/60 208/102/60
f 198/36/61 206/104/61 207/103/61
f 209/101/62 206/104/62 198/36/62
f 209/101/54 208/102/54 204/105/54
f 204/105/53 208/102/53 207/103/53
f 203/106/52 207/103/52 206/104/52
f 206/104/51 209/101/51 205/108/51
f 202/107/63 205/108/63 197/98/63
f 195/99/64 203/106/64 202/107/64
f 196/97/65 204/105/65 203/106/65
f 205/108/66 204/105/66 196/97/66
f 174/79/67 217/77/67 215/109/67
f 175/81/44 217/77/44 218/78/44
f 170/73/44 215/109/44 210/75/44
f 173/74/68 177/80/68 218/78/68
f 151/61/23 214/66/23 210/75/23
f 173/74/44 216/71/44 212/1/44
f 139/42/44 212/1/44 211/2/44
f 26/45/1 103/1/1 6/3/1
f 3/7/2 20/4/2 4/6/2
f 45/57/2 20/4/2 52/8/2
f 30/42/3 36/9/3 11/11/3
f 5/5/2 39/12/2 4/6/2
f 3/7/4 4/6/4 53/15/4
f 10/20/5 14/16/5 12/18/5
f 7/30/6 18/19/6 10/20/6
f 33/39/3 20/4/3 31/22/3
f 13/17/7 17/23/7 12/18/7
f 33/39/4 25/25/4 29/27/4
f 7/30/4 10/20/4 8/24/4
f 19/29/69 1/28/69 17/23/69
f 33/39/4 19/29/4 13/17/4
f 1/28/70 25/25/70 18/19/70
f 17/23/9 18/19/9 8/24/9
f 89/36/10 92/31/10 28/33/10
f 31/22/3 16/21/3 36/9/3
f 15/41/3 31/22/3 21/34/3
f 24/38/11 90/35/11 28/33/11
f 23/40/12 91/37/12 24/38/12
f 25/25/4 33/39/4 14/16/4
f 27/32/4 23/40/4 28/33/4
f 19/29/3 33/39/3 15/41/3
f 9/60/3 21/34/3 30/42/3
f 25/25/4 5/5/4 32/26/4
f 35/43/4 5/5/4 34/44/4
f 20/4/4 33/39/4 34/44/4
f 92/31/13 91/37/13 27/32/13
f 107/71/1 103/1/1 63/46/1
f 2/65/14 26/45/14 38/48/14
f 49/84/15 39/12/15 72/50/15
f 44/58/16 48/51/16 59/53/16
f 43/59/17 15/41/17 47/54/17
f 1/28/17 19/29/17 37/56/17
f 51/13/2 39/12/2 52/8/2
f 16/21/2 20/4/2 44/58/2
f 46/55/18 19/29/18 43/59/18
f 21/34/19 9/60/19 47/54/19
f 11/11/20 22/10/20 41/62/20
f 49/84/21 25/25/21 37/56/21
f 26/45/14 6/3/14 50/47/14
f 102/2/22 104/64/22 6/3/22
f 101/75/23 2/65/23 105/66/23
f 54/14/2 55/67/2 53/15/2
f 52/8/14 3/7/14 56/68/14
f 4/6/15 51/13/15 54/14/15
f 51/13/24 52/8/24 55/67/24
f 58/70/2 57/69/2 60/52/2
f 60/52/25 48/51/25 58/70/25
f 22/10/26 16/21/26 58/70/26
f 57/69/27 16/21/27 59/53/27
f 109/78/71 107/71/71 67/72/71
f 63/46/1 26/45/1 61/73/1
f 62/76/1 9/60/1 64/74/1
f 106/109/1 101/75/1 62/76/1
f 65/79/1 108/77/1 67/72/1
f 63/46/29 61/73/29 67/72/29
f 66/81/30 62/76/30 68/80/30
f 106/109/72 62/76/72 108/77/72
f 72/50/32 71/49/32 76/83/32
f 70/86/15 25/25/15 72/50/15
f 39/12/15 5/5/15 71/49/15
f 5/5/15 25/25/15 69/85/15
f 80/90/15 76/83/15 79/87/15
f 70/86/17 72/50/17 74/88/17
f 75/82/2 71/49/2 73/89/2
f 69/85/33 70/86/33 73/89/33
f 84/95/3 80/90/3 83/91/3
f 74/88/15 76/83/15 78/92/15
f 79/87/15 75/82/15 77/93/15
f 73/89/15 74/88/15 77/93/15
f 81/96/15 82/94/15 83/91/15
f 78/92/2 80/90/2 82/94/2
f 79/87/17 77/93/17 83/91/17
f 81/96/24 77/93/24 82/94/24
f 32/26/13 35/43/13 88/98/13
f 87/97/12 35/43/12 86/99/12
f 86/99/11 34/44/11 85/100/11
f 29/27/10 32/26/10 85/100/10
f 91/37/34 92/31/34 99/102/34
f 98/103/35 90/35/35 99/102/35
f 97/104/36 89/36/36 98/103/36
f 92/31/37 89/36/37 100/101/37
f 96/108/13 95/105/13 100/101/13
f 99/102/12 95/105/12 98/103/12
f 98/103/11 94/106/11 97/104/11
f 93/107/10 96/108/10 97/104/10
f 85/100/38 88/98/38 93/107/38
f 94/106/39 86/99/39 93/107/39
f 95/105/40 87/97/40 94/106/40
f 88/98/41 87/97/41 96/108/41
f 61/73/73 106/109/73 65/79/73
f 108/77/1 66/81/1 109/78/1
f 2/65/1 101/75/1 61/73/1
f 68/80/74 64/74/74 109/78/74
f 9/60/23 101/75/23 42/61/23
f 30/42/1 103/1/1 64/74/1
f 103/1/1 30/42/1 102/2/1
f 211/2/44 212/1/44 115/3/44
f 114/5/2 129/4/2 113/6/2
f 154/57/2 161/8/2 129/4/2
f 131/10/24 145/9/24 120/11/24
f 114/5/2 113/6/2 148/12/2
f 112/7/45 162/15/45 113/6/45
f 122/17/46 123/16/46 121/18/46
f 123/16/47 127/19/47 119/20/47
f 142/39/24 140/22/24 129/4/24
f 122/17/48 121/18/48 126/23/48
f 142/39/45 138/27/45 134/25/45
f 116/30/45 117/24/45 119/20/45
f 128/29/75 126/23/75 110/28/75
f 142/39/45 122/17/45 128/29/45
f 110/28/76 127/19/76 134/25/76
f 126/23/50 117/24/50 127/19/50
f 198/36/51 137/33/51 201/31/51
f 140/22/24 145/9/24 125/21/24
f 124/41/24 130/34/24 140/22/24
f 198/36/52 199/35/52 137/33/52
f 199/35/53 200/37/53 133/38/53
f 134/25/45 123/16/45 142/39/45
f 136/32/45 137/33/45 132/40/45
f 128/29/24 124/41/24 142/39/24
f 145/9/24 130/34/24 139/42/24
f 134/25/45 141/26/45 114/5/45
f 129/4/45 114/5/45 143/44/45
f 129/4/45 143/44/45 142/39/45
f 201/31/54 136/32/54 200/37/54
f 135/45/44 212/1/44 172/46/44
f 111/65/14 147/48/14 135/45/14
f 158/84/15 181/50/15 148/12/15
f 153/58/26 168/53/26 157/51/26
f 130/34/17 124/41/17 156/54/17
f 110/28/17 146/56/17 128/29/17
f 154/57/2 148/12/2 161/8/2
f 154/57/2 129/4/2 153/58/2
f 128/29/18 155/55/18 124/41/18
f 118/60/19 130/34/19 151/61/19
f 157/51/20 131/10/20 150/62/20
f 110/28/21 134/25/21 146/56/21
f 135/45/14 159/47/14 115/3/14
f 211/2/22 115/3/22 213/64/22
f 210/75/23 214/66/23 111/65/23
f 163/14/2 162/15/2 164/67/2
f 161/8/14 165/68/14 112/7/14
f 113/6/15 163/14/15 160/13/15
f 160/13/3 164/67/3 161/8/3
f 168/53/2 166/69/2 169/52/2
f 131/10/25 157/51/25 167/70/25
f 131/10/16 167/70/16 125/21/16
f 153/58/27 125/21/27 168/53/27
f 172/46/77 216/71/77 176/72/77
f 111/65/44 135/45/44 170/73/44
f 139/42/44 118/60/44 173/74/44
f 118/60/44 210/75/44 171/76/44
f 218/78/44 217/77/44 176/72/44
f 172/46/56 176/72/56 170/73/56
f 173/74/57 171/76/57 177/80/57
f 215/109/78 217/77/78 171/76/78
f 181/50/33 185/83/33 180/49/33
f 158/84/15 134/25/15 181/50/15
f 148/12/15 180/49/15 114/5/15
f 114/5/15 178/85/15 134/25/15
f 185/83/15 189/90/15 184/82/15
f 179/86/17 183/88/17 181/50/17
f 178/85/2 180/49/2 182/89/2
f 178/85/32 182/89/32 179/86/32
f 188/87/24 189/90/24 192/91/24
f 183/88/15 187/92/15 185/83/15
f 182/89/15 184/82/15 186/93/15
f 182/89/15 186/93/15 183/88/15
f 190/96/15 192/91/15 191/94/15
f 187/92/2 191/94/2 189/90/2
f 188/87/17 192/91/17 186/93/17
f 187/92/3 186/93/3 191/94/3
f 141/26/54 197/98/54 144/43/54
f 143/44/53 144/43/53 195/99/53
f 138/27/52 143/44/52 194/100/52
f 138/27/51 194/100/51 141/26/51
f 200/37/59 208/102/59 201/31/59
f 200/37/60 199/35/60 208/102/60
f 199/35/61 198/36/61 207/103/61
f 201/31/79 209/101/79 198/36/79
f 205/108/54 209/101/54 204/105/54
f 203/106/53 204/105/53 207/103/53
f 202/107/52 203/106/52 206/104/52
f 202/107/51 206/104/51 205/108/51
f 194/100/63 202/107/63 197/98/63
f 194/100/64 195/99/64 202/107/64
f 195/99/65 196/97/65 203/106/65
f 197/98/66 205/108/66 196/97/66
f 170/73/80 174/79/80 215/109/80
f 177/80/44 175/81/44 218/78/44
f 111/65/44 170/73/44 210/75/44
f 216/71/81 173/74/81 218/78/81
f 118/60/23 151/61/23 210/75/23
f 139/42/44 173/74/44 212/1/44
f 120/11/44 139/42/44 211/2/44
usemtl Material.003
f 41/62/82 104/64/82 102/2/82
f 211/2/82 213/64/82 150/62/82
f 11/11/82 41/62/82 102/2/82
f 120/11/82 211/2/82 150/62/82

View File

@@ -0,0 +1,6 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
map_Kd tmp.png

View File

@@ -0,0 +1,7 @@
mtllib invalid-file-aaa.mtl invalid-file-bbb.mtl mtllib-multiple-files-issue-112.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

7
models/norm-texopt.mtl Normal file
View File

@@ -0,0 +1,7 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3
norm -bm 3 normalmap.jpg

7
models/norm-texopt.obj Normal file
View File

@@ -0,0 +1,7 @@
mtllib norm-texopt.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

19
models/pbr-mat-ext.mtl Normal file
View File

@@ -0,0 +1,19 @@
# .MTL with PBR extension.
newmtl pbr
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
Ke 0.1 0.1 0.1
Pr 0.2
Pm 0.3
Ps 0.4
Pc 0.5
Pcr 0.6
aniso 0.7
anisor 0.8
map_Pr roughness.tex
map_Pm metallic.tex
map_Ps sheen.tex
map_Ke emissive.tex
norm normalmap.tex

10
models/pbr-mat-ext.obj Normal file
View File

@@ -0,0 +1,10 @@
mtllib pbr-mat-ext.mtl
o floor
usemtl pbr
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
f 1 2 3 4

25
models/refl.mtl Normal file
View File

@@ -0,0 +1,25 @@
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
refl reflection.tga
newmtl red
Ka 0 0 0
Kd 1 0 0
Ks 0 0 0
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue
Ka 0 0 0
Kd 0 0 1
Ks 0 0 0
newmtl light
Ka 20 20 20
Kd 1 1 1
Ks 0 0 0

32
models/refl.obj Normal file
View File

@@ -0,0 +1,32 @@
# Test for `refl` material parameter
mtllib refl.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g front cube
usemtl white
f 1 2 3 4
g back cube
# expects white material
f 8 7 6 5
g right cube
usemtl red
f 4 3 7 8
g top cube
usemtl white
f 5 1 4 8
g left cube
usemtl green
f 5 6 2 1
g bottom cube
usemtl white
f 2 6 7 3
# 6 elements

View File

@@ -0,0 +1,22 @@
# from tinyobjloader issue #29
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
v 4.000000 0.000000 -3.255298
v 4.000000 2.000000 -3.255298
#vn 0.000000 0.000000 1.000000
#vn 0.000000 0.000000 1.000000
#vn 0.276597 0.000000 0.960986
#vn 0.276597 0.000000 0.960986
#vn 0.531611 0.000000 0.846988
#vn 0.531611 0.000000 0.846988
# 6 vertices
# 6 normals
g all
s 1
f 1//1 2//2 3//3 4//4
f 4//4 3//3 5//5

View File

@@ -0,0 +1,24 @@
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
newmtl red
Ka 0 0 0
Kd 1 0 0
Ks 0 0 0
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue
Ka 0 0 0
Kd 0 0 1
Ks 0 0 0
newmtl light
Ka 20 20 20
Kd 1 1 1
Ks 0 0 0

View File

@@ -0,0 +1,35 @@
mtllib smoothing-normal.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g front cube
usemtl white
s 1
f 1 2 3 4
#g bottom cube
#usemtl white
s 1
f 2 6 7 3
g back cube
# expects white material
s off
f 8 7 6 5
#g right cube
#usemtl red
#f 4 3 7 8
#g top cube
#usemtl white
#f 5 1 4 8
#g left cube
#usemtl green
#f 5 6 2 1
# 6 elements

View File

@@ -0,0 +1,28 @@
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
# filename with white space.
map_Kd texture 01.png
newmtl red
Ka 0 0 0
Kd 1 0 0
Ks 0 0 0
# texture option + filename with white space.
bump -bm 2 bump 01.png
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue
Ka 0 0 0
Kd 0 0 1
Ks 0 0 0
newmtl light
Ka 20 20 20
Kd 1 1 1
Ks 0 0 0

View File

@@ -0,0 +1,31 @@
mtllib texture-filename-with-whitespace.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g front cube
usemtl white
f 1 2 3 4
g back cube
# expects white material
f 8 7 6 5
g right cube
usemtl red
f 4 3 7 8
g top cube
usemtl white
f 5 1 4 8
g left cube
usemtl green
f 5 6 2 1
g bottom cube
usemtl white
f 2 6 7 3
# 6 elements

View File

@@ -0,0 +1,36 @@
newmtl default
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3
map_Ka -clamp on ambient.jpg
map_Kd -o 0.1 diffuse.jpg
map_Ks -s 0.1 0.2 specular.jpg
map_Ns -t 0.1 0.2 0.3 specular_highlight.jpg
map_bump -bm 3 bumpmap.jpg
newmtl bm2
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3
# blendu
map_Kd -blendu on diffuse.jpg
map_Ks -blendv off specular.jpg
map_Ns -mm 0.1 0.3 specular_highlight.jpg
# -bm after filename
map_bump -imfchan r bumpmap2.jpg -bm 1.5
newmtl bm3
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Kt 0.1 0.2 0.3
# type
map_Kd -type sphere diffuse.jpg
map_Ks -type cube_top specular.jpg
map_Ns -type cube_bottom specular_highlight.jpg
map_Ka -type cube_left ambient.jpg
map_d -type cube_right alpha.jpg
map_bump -type cube_front bump.jpg
disp -type cube_back displacement.jpg

View File

@@ -0,0 +1,7 @@
mtllib texture-options-issue-85.mtl
o Test
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
usemtl default
f 1 2 3

View File

@@ -0,0 +1,13 @@
newmtl Material.001
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
d 0.75
Tr 0.5
newmtl Material.002
Ka 0 0 0
Kd 0 0 0
Ks 0 0 0
Tr 0.5
d 0.75

View File

@@ -0,0 +1,817 @@
# https://github.com/syoyo/tinyobjloader/issues/68
# Blender v2.73 (sub 0) OBJ File: 'enemy.blend'
# www.blender.org
mtllib tr-and-d-issue-43.mtl
o Cube
v 1.864151 -1.219172 -5.532511
v 0.575869 -0.666304 5.896140
v 0.940448 1.000000 -1.971128
v 1.620345 1.000000 -5.815706
v 1.864152 1.000000 -6.334323
v 0.575869 -0.129842 5.896143
v 5.440438 -1.462153 -5.818601
v 4.896782 -1.462153 -2.744413
v 1.000825 -0.677484 1.899605
v 5.440438 -1.246362 -5.818600
v 1.000825 0.852342 1.899608
v 4.896782 -1.246362 -2.744412
v 1.160660 -0.450871 -2.356325
v 1.704316 -0.450871 -5.430513
v 1.000825 -0.351920 -1.293797
v 1.000825 1.000000 -1.293794
v 1.160660 -0.877888 -2.356326
v 1.704316 -0.877888 -5.430514
v 1.000825 -1.219172 -1.452514
v 1.000825 1.000000 -1.452511
v 1.000825 -0.351920 1.759410
v 1.000825 1.000000 1.759413
v 9.097919 1.221145 -6.212147
v 8.356775 1.221145 -2.021231
v 1.864151 -0.109586 -6.334325
v 0.575869 -0.398073 5.896141
v 9.097919 0.943958 -6.212148
v 8.356775 0.943958 -2.021233
v 1.061916 0.113661 -1.797961
v 1.000825 0.161258 1.899606
v 1.000825 0.324040 -1.293795
v 1.803060 0.113661 -5.988876
v 1.000825 -0.109586 -1.452513
v 1.061916 0.776753 -1.797960
v 1.803061 0.776753 -5.988875
v 1.000825 0.324040 1.759412
v 0.000825 -1.219172 -5.532512
v 0.000825 -0.666304 5.896139
v 0.000826 1.000000 -6.334325
v 0.000825 -0.129842 5.896140
v 0.000825 0.852342 1.899606
v 0.000825 -0.677484 1.899604
v 0.000825 -0.351920 -1.293797
v 0.000825 1.000000 -1.293796
v 0.000825 1.000000 -1.452513
v 0.000825 -1.219172 -1.452515
v 0.000825 -0.351920 1.759409
v 0.000825 1.000000 1.759411
v 0.000826 -0.109586 -6.334326
v 0.000825 -0.398073 5.896140
v 0.152918 1.000000 -5.815708
v 0.152917 1.000000 -1.971130
v 0.940448 1.168419 -1.971128
v 1.620345 1.168419 -5.815706
v 0.152918 1.168419 -5.815708
v 0.152917 1.168419 -1.971130
v 0.921118 1.091883 -1.050430
v 0.921118 1.091883 1.516050
v 0.080533 1.091883 -1.050432
v 0.080533 1.091883 1.516048
v 0.613003 -0.553430 5.546911
v 0.963691 -0.559956 2.248834
v 0.613003 -0.396857 5.546912
v 0.963691 -0.070362 2.248835
v 1.499370 -0.994317 3.966028
v 1.850058 -0.997914 0.667950
v 1.499370 -0.908021 3.966029
v 1.850058 -0.728071 0.667951
v 1.601022 0.760960 -6.334324
v 1.601021 0.129454 -6.334325
v 0.263955 0.760960 -6.334325
v 0.263955 0.129454 -6.334325
v 1.334809 0.760960 -7.515329
v 1.334809 0.129455 -7.515330
v 0.530168 0.760960 -7.515330
v 0.530168 0.129455 -7.515330
v 1.192720 0.649445 -7.515329
v 1.192720 0.240971 -7.515330
v 0.672258 0.649445 -7.515330
v 0.672258 0.240971 -7.515330
v 1.192719 0.649444 -6.524630
v 1.192719 0.240970 -6.524631
v 0.672257 0.649444 -6.524631
v 0.672257 0.240970 -6.524631
v 3.851026 0.431116 -1.883326
v 3.851026 0.946662 -1.883325
v 4.592170 0.946662 -6.074241
v 4.592169 0.431116 -6.074242
v 4.995714 0.561404 -1.918362
v 4.995714 1.016394 -1.918360
v 5.736857 1.016394 -6.109276
v 5.736857 0.561404 -6.109277
v 3.975454 0.471731 -2.162156
v 3.975454 0.919244 -2.162155
v 4.618796 0.919244 -5.800034
v 4.618795 0.471730 -5.800035
v 4.969088 0.584825 -2.192568
v 4.969088 0.979775 -2.192567
v 5.612430 0.979775 -5.830446
v 5.612429 0.584825 -5.830447
v 0.864214 -0.673890 3.184381
v 0.864213 0.489129 3.184384
v 0.864213 -0.018552 3.184383
v 0.000825 0.489129 3.184382
v 0.000825 -0.673890 3.184381
v 0.850955 -0.557858 3.309075
v 0.850955 -0.175321 3.309076
v 1.737321 -0.996758 1.728192
v 1.737321 -0.785920 1.728193
v -1.864151 -1.219172 -5.532511
v -0.575869 -0.666304 5.896140
v -0.940448 1.000000 -1.971128
v -1.620345 1.000000 -5.815706
v -1.864152 1.000000 -6.334323
v -0.575869 -0.129842 5.896143
v -5.440438 -1.462153 -5.818601
v -4.896782 -1.462153 -2.744413
v -1.000825 -0.677484 1.899605
v -5.440438 -1.246362 -5.818600
v -1.000825 0.852342 1.899608
v -4.896782 -1.246362 -2.744412
v -1.160660 -0.450871 -2.356325
v -1.704316 -0.450871 -5.430513
v -1.000825 -0.351920 -1.293797
v -1.000825 1.000000 -1.293794
v -1.160660 -0.877888 -2.356326
v -1.704316 -0.877888 -5.430514
v -1.000825 -1.219172 -1.452514
v -1.000825 1.000000 -1.452511
v -1.000825 -0.351920 1.759410
v -1.000825 1.000000 1.759413
v -9.097919 1.221145 -6.212147
v -8.356775 1.221145 -2.021231
v -1.864151 -0.109586 -6.334325
v -0.575869 -0.398073 5.896141
v -9.097919 0.943958 -6.212148
v -8.356775 0.943958 -2.021233
v -1.061916 0.113661 -1.797961
v -1.000825 0.161258 1.899606
v -1.000825 0.324040 -1.293795
v -1.803060 0.113661 -5.988876
v -1.000825 -0.109586 -1.452513
v -1.061916 0.776753 -1.797960
v -1.803061 0.776753 -5.988875
v -1.000825 0.324040 1.759412
v -0.000825 -1.219172 -5.532512
v -0.000825 -0.666304 5.896139
v -0.000826 1.000000 -6.334325
v -0.000825 -0.129842 5.896140
v -0.000825 0.852342 1.899606
v -0.000825 -0.677484 1.899604
v -0.000825 -0.351920 -1.293797
v -0.000825 1.000000 -1.293796
v -0.000825 1.000000 -1.452513
v -0.000825 -1.219172 -1.452515
v -0.000825 -0.351920 1.759409
v -0.000825 1.000000 1.759411
v -0.000826 -0.109586 -6.334326
v -0.000825 -0.398073 5.896140
v -0.152918 1.000000 -5.815708
v -0.152917 1.000000 -1.971130
v -0.940448 1.168419 -1.971128
v -1.620345 1.168419 -5.815706
v -0.152918 1.168419 -5.815708
v -0.152917 1.168419 -1.971130
v -0.921118 1.091883 -1.050430
v -0.921118 1.091883 1.516050
v -0.080533 1.091883 -1.050432
v -0.080533 1.091883 1.516048
v -0.613003 -0.553430 5.546911
v -0.963691 -0.559956 2.248834
v -0.613003 -0.396857 5.546912
v -0.963691 -0.070362 2.248835
v -1.499370 -0.994317 3.966028
v -1.850058 -0.997914 0.667950
v -1.499370 -0.908021 3.966029
v -1.850058 -0.728071 0.667951
v -1.601022 0.760960 -6.334324
v -1.601021 0.129454 -6.334325
v -0.263955 0.760960 -6.334325
v -0.263955 0.129454 -6.334325
v -1.334809 0.760960 -7.515329
v -1.334809 0.129455 -7.515330
v -0.530168 0.760960 -7.515330
v -0.530168 0.129455 -7.515330
v -1.192720 0.649445 -7.515329
v -1.192720 0.240971 -7.515330
v -0.672258 0.649445 -7.515330
v -0.672258 0.240971 -7.515330
v -1.192719 0.649444 -6.524630
v -1.192719 0.240970 -6.524631
v -0.672257 0.649444 -6.524631
v -0.672257 0.240970 -6.524631
v -3.851026 0.431116 -1.883326
v -3.851026 0.946662 -1.883325
v -4.592170 0.946662 -6.074241
v -4.592169 0.431116 -6.074242
v -4.995714 0.561404 -1.918362
v -4.995714 1.016394 -1.918360
v -5.736857 1.016394 -6.109276
v -5.736857 0.561404 -6.109277
v -3.975454 0.471731 -2.162156
v -3.975454 0.919244 -2.162155
v -4.618796 0.919244 -5.800034
v -4.618795 0.471730 -5.800035
v -4.969088 0.584825 -2.192568
v -4.969088 0.979775 -2.192567
v -5.612430 0.979775 -5.830446
v -5.612429 0.584825 -5.830447
v -0.864214 -0.673890 3.184381
v -0.864213 0.489129 3.184384
v -0.864213 -0.018552 3.184383
v -0.000825 0.489129 3.184382
v -0.000825 -0.673890 3.184381
v -0.850955 -0.557858 3.309075
v -0.850955 -0.175321 3.309076
v -1.737321 -0.996758 1.728192
v -1.737321 -0.785920 1.728193
vt 0.135351 -0.558072
vt 0.003035 -0.363507
vt 0.092282 -0.976844
vt -0.081322 0.947351
vt 0.100058 1.958891
vt 0.050091 1.852185
vt -0.092752 1.055565
vt -0.251711 1.059474
vt 0.075587 0.041384
vt -0.086008 0.279003
vt -0.086212 0.249830
vt -0.276044 1.968137
vt -0.246101 1.859467
vt 0.009828 1.911388
vt -0.133014 1.114769
vt 0.413322 1.261595
vt 0.299103 0.624605
vt 1.243955 0.407183
vt 0.515404 1.111487
vt 1.358173 1.044173
vt -0.081553 0.914324
vt 0.080042 0.676706
vt 0.401185 0.474498
vt 1.295541 0.331328
vt 0.365315 1.568841
vt 0.299111 1.575740
vt 0.143401 0.707357
vt 0.629403 1.011947
vt 0.449192 0.167251
vt 1.409760 0.968317
vt 0.986264 1.738667
vt 1.573373 1.877873
vt 1.417663 1.009490
vt 0.237182 -0.196235
vt 0.721785 1.030226
vt 0.830554 0.870285
vt 0.877494 1.898608
vt 1.351399 1.106930
vt 0.183935 0.557301
vt 1.507109 1.975312
vt 0.241636 0.439088
vt 0.114297 -0.045011
vt 0.140593 1.808834
vt -0.015118 0.940452
vt 0.156405 -1.071134
vt 0.164119 -0.998223
vt 0.040336 -1.068281
vt 0.104459 -1.162571
vt -0.165787 1.882802
vt -0.014821 1.660811
vt -0.287852 0.283965
vt -0.293374 0.366508
vt -0.289630 0.900550
vt 0.035337 -0.191272
vt 0.247348 0.172213
vt 0.253300 1.021193
vt -0.283166 0.952313
vt -0.283398 0.919286
vt 0.039792 0.444050
vt 0.314806 -0.339851
vt 0.112962 -0.334889
vt -0.288056 0.254793
vt -0.023788 -0.973990
vt -0.155922 -0.359599
vt 0.220528 -1.165425
vt 0.108710 -0.748730
vt -0.286364 1.918670
vt -0.291973 1.118678
vt -0.119962 0.896379
vt -0.123707 0.362337
vt 0.162891 -0.598569
vt 0.467532 -0.853353
vt 0.201549 -1.053262
vt 0.161663 -0.198915
vt 0.267667 -0.752638
vt 0.278705 -0.371021
vt 0.526390 -0.542053
vt 0.483821 -0.479457
vt 0.488162 -0.883689
vt 0.500110 -0.105561
vt 0.564618 -0.200418
vt -0.110331 2.127229
vt 0.040636 1.905238
vt -0.010786 1.578087
vt 0.104092 1.876168
vt 0.255058 1.654176
vt -0.054992 2.087323
vt 0.203048 1.901245
vt 0.052081 2.123235
vt 0.042658 1.943733
vt -0.056437 1.881175
vt 0.147710 1.941151
vt 0.050060 2.084741
vt 0.146264 1.735002
vt 0.041212 1.737584
vt 0.048615 1.878591
vt 0.663065 1.872485
vt 0.786311 1.691257
vt 0.507355 1.004102
vt 0.630601 0.822874
vt 0.955144 1.689498
vt 0.860727 1.828333
vt 0.725565 1.074543
vt 0.819981 0.935708
vt 0.674594 1.805657
vt 0.539432 1.051867
vt 0.646413 0.894554
vt 0.781576 1.648344
vt 0.240127 -0.712141
vn 0.994400 0.000000 0.105700
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.984700 0.000000 0.174100
vn 0.211800 0.976600 0.037500
vn -0.103300 0.000000 -0.994600
vn 0.103300 -0.000000 0.994600
vn 0.911400 0.378700 0.161200
vn -0.157300 -0.987200 -0.027800
vn 0.113700 -0.993300 0.020100
vn 0.030600 -0.000000 0.999500
vn -0.061100 0.998100 -0.010800
vn -0.030600 0.000000 -0.999500
vn -0.000000 -0.000000 1.000000
vn 0.000000 0.000000 -1.000000
vn -0.755400 0.655300 0.000000
vn 0.000000 -1.000000 0.000000
vn -0.000000 -0.180000 0.983700
vn 0.000000 -0.395500 -0.918500
vn -0.000000 0.688500 0.725200
vn 0.000000 -0.585700 -0.810500
vn -0.000000 0.974900 0.222500
vn -0.000000 -1.000000 0.002800
vn -1.000000 0.000000 -0.000000
vn -0.000000 0.935500 0.353200
vn 0.755400 0.655300 0.000000
vn 0.000000 0.935500 -0.353200
vn 0.673800 0.724900 0.143400
vn 0.872300 -0.000000 0.489100
vn -0.872300 0.000000 -0.489100
vn -0.518300 -0.853500 -0.054200
vn -0.975500 0.000000 -0.219900
vn 0.975500 0.000000 -0.219900
vn -0.913200 0.000000 -0.407500
vn -0.436900 0.896200 -0.077300
vn -0.995300 -0.000000 0.096600
vn -0.297300 -0.953400 -0.052600
vn 0.473900 -0.876600 0.083800
vn 0.913200 0.000000 0.407500
vn 0.342200 0.937700 0.060500
vn 0.995300 -0.000000 -0.096600
vn -0.519200 -0.853000 -0.054300
vn 0.722400 0.676400 0.143800
vn -0.994400 0.000000 0.105700
vn -0.984700 0.000000 0.174100
vn -0.211800 0.976600 0.037500
vn 0.103300 0.000000 -0.994600
vn -0.103300 -0.000000 0.994600
vn -0.911400 0.378700 0.161200
vn 0.157300 -0.987200 -0.027800
vn -0.113700 -0.993300 0.020100
vn -0.030600 -0.000000 0.999500
vn 0.061100 0.998100 -0.010800
vn 0.030600 0.000000 -0.999500
vn -0.691900 0.713200 0.112500
vn -0.872300 -0.000000 0.489100
vn 0.872300 0.000000 -0.489100
vn 0.518300 -0.853500 -0.054200
vn 0.913200 0.000000 -0.407500
vn 0.436900 0.896200 -0.077300
vn 0.995300 0.000000 0.096600
vn 0.297300 -0.953300 -0.052600
vn -0.473900 -0.876600 0.083800
vn -0.913200 -0.000000 0.407500
vn -0.342200 0.937700 0.060500
vn -0.995300 -0.000000 -0.096600
vn 0.519200 -0.853000 -0.054300
vn -0.714800 0.690100 0.113700
vn 0.974400 0.089700 0.206200
vn 0.870400 0.288400 0.399100
vn 0.691900 0.713200 0.112500
vn -0.518000 -0.853700 -0.053400
vn -0.519700 -0.852700 -0.053600
vn 0.714800 0.690100 0.113700
vn -0.974400 0.089700 0.206200
vn -0.870400 0.288400 0.399100
vn -0.673800 0.724900 0.143400
vn 0.518000 -0.853700 -0.053400
vn 0.297300 -0.953400 -0.052600
vn 0.519700 -0.852700 -0.053600
vn -0.722400 0.676400 0.143800
vn -0.000000 0.962300 0.272000
usemtl Material.001
s off
f 103/1/1 102/2/1 6/3/1
f 20/4/2 5/5/2 4/6/2
f 20/4/2 3/7/2 52/8/2
f 36/9/3 22/10/3 11/11/3
f 39/12/2 51/13/2 4/6/2
f 4/6/4 54/14/4 53/15/4
f 14/16/5 13/17/5 12/18/5
f 18/19/6 14/16/6 10/20/6
f 20/4/3 16/21/3 31/22/3
f 17/23/7 8/24/7 12/18/7
f 25/25/4 32/26/4 29/27/4
f 10/20/4 12/18/4 8/24/4
f 1/28/8 18/19/8 17/23/8
f 19/29/4 17/23/4 13/17/4
f 25/25/4 14/16/4 18/19/4
f 18/19/9 7/30/9 8/24/9
f 92/31/10 27/32/10 28/33/10
f 16/21/3 22/10/3 36/9/3
f 31/22/3 36/9/3 21/34/3
f 90/35/11 89/36/11 28/33/11
f 91/37/12 90/35/12 24/38/12
f 33/39/4 13/17/4 14/16/4
f 23/40/4 24/38/4 28/33/4
f 33/39/3 31/22/3 15/41/3
f 21/34/3 36/9/3 30/42/3
f 5/5/4 35/43/4 32/26/4
f 5/5/4 20/4/4 34/44/4
f 33/39/4 29/27/4 34/44/4
f 91/37/13 23/40/13 27/32/13
f 103/1/1 26/45/1 63/46/1
f 26/45/14 50/47/14 38/48/14
f 39/12/15 71/49/15 72/50/15
f 48/51/16 60/52/16 59/53/16
f 15/41/17 21/34/17 47/54/17
f 19/29/17 46/55/17 37/56/17
f 39/12/2 45/57/2 52/8/2
f 20/4/2 45/57/2 44/58/2
f 19/29/18 15/41/18 43/59/18
f 9/60/19 42/61/19 47/54/19
f 22/10/20 48/51/20 41/62/20
f 25/25/21 1/28/21 37/56/21
f 6/3/14 40/63/14 50/47/14
f 104/64/22 40/63/22 6/3/22
f 2/65/23 38/48/23 105/66/23
f 55/67/2 56/68/2 53/15/2
f 3/7/14 53/15/14 56/68/14
f 51/13/15 55/67/15 54/14/15
f 52/8/24 56/68/24 55/67/24
f 57/69/2 59/53/2 60/52/2
f 48/51/25 22/10/25 58/70/25
f 16/21/26 57/69/26 58/70/26
f 16/21/27 44/58/27 59/53/27
f 107/71/28 63/46/28 67/72/28
f 26/45/1 2/65/1 61/73/1
f 9/60/1 30/42/1 64/74/1
f 101/75/1 9/60/1 62/76/1
f 108/77/1 109/78/1 67/72/1
f 61/73/29 65/79/29 67/72/29
f 62/76/30 64/74/30 68/80/30
f 62/76/31 66/81/31 108/77/31
f 71/49/32 75/82/32 76/83/32
f 25/25/15 49/84/15 72/50/15
f 5/5/15 69/85/15 71/49/15
f 25/25/15 70/86/15 69/85/15
f 76/83/15 75/82/15 79/87/15
f 72/50/17 76/83/17 74/88/17
f 71/49/2 69/85/2 73/89/2
f 70/86/33 74/88/33 73/89/33
f 80/90/3 79/87/3 83/91/3
f 76/83/15 80/90/15 78/92/15
f 75/82/15 73/89/15 77/93/15
f 74/88/15 78/92/15 77/93/15
f 82/94/15 84/95/15 83/91/15
f 80/90/2 84/95/2 82/94/2
f 77/93/17 81/96/17 83/91/17
f 77/93/24 78/92/24 82/94/24
f 35/43/13 87/97/13 88/98/13
f 35/43/12 34/44/12 86/99/12
f 34/44/11 29/27/11 85/100/11
f 32/26/10 88/98/10 85/100/10
f 92/31/34 100/101/34 99/102/34
f 90/35/35 91/37/35 99/102/35
f 89/36/36 90/35/36 98/103/36
f 89/36/37 97/104/37 100/101/37
f 95/105/13 99/102/13 100/101/13
f 95/105/12 94/106/12 98/103/12
f 94/106/11 93/107/11 97/104/11
f 96/108/10 100/101/10 97/104/10
f 88/98/38 96/108/38 93/107/38
f 86/99/39 85/100/39 93/107/39
f 87/97/40 86/99/40 94/106/40
f 87/97/41 95/105/41 96/108/41
f 106/109/42 108/77/42 65/79/42
f 66/81/1 68/80/1 109/78/1
f 101/75/1 106/109/1 61/73/1
f 64/74/43 107/71/43 109/78/43
f 101/75/23 105/66/23 42/61/23
f 103/1/1 107/71/1 64/74/1
f 30/42/1 11/11/1 102/2/1
f 212/1/44 135/45/44 115/3/44
f 129/4/2 112/7/2 113/6/2
f 161/8/2 112/7/2 129/4/2
f 145/9/24 139/42/24 120/11/24
f 113/6/2 160/13/2 148/12/2
f 162/15/45 163/14/45 113/6/45
f 123/16/46 119/20/46 121/18/46
f 127/19/47 116/30/47 119/20/47
f 140/22/24 125/21/24 129/4/24
f 121/18/48 117/24/48 126/23/48
f 138/27/45 141/26/45 134/25/45
f 117/24/45 121/18/45 119/20/45
f 126/23/49 127/19/49 110/28/49
f 122/17/45 126/23/45 128/29/45
f 127/19/45 123/16/45 134/25/45
f 117/24/50 116/30/50 127/19/50
f 137/33/51 136/32/51 201/31/51
f 145/9/24 131/10/24 125/21/24
f 130/34/24 145/9/24 140/22/24
f 199/35/52 133/38/52 137/33/52
f 200/37/53 132/40/53 133/38/53
f 123/16/45 122/17/45 142/39/45
f 137/33/45 133/38/45 132/40/45
f 124/41/24 140/22/24 142/39/24
f 130/34/24 118/60/24 139/42/24
f 141/26/45 144/43/45 114/5/45
f 114/5/45 144/43/45 143/44/45
f 143/44/45 138/27/45 142/39/45
f 136/32/54 132/40/54 200/37/54
f 212/1/44 216/71/44 172/46/44
f 147/48/14 159/47/14 135/45/14
f 181/50/15 180/49/15 148/12/15
f 168/53/26 169/52/26 157/51/26
f 124/41/17 152/59/17 156/54/17
f 146/56/17 155/55/17 128/29/17
f 148/12/2 160/13/2 161/8/2
f 129/4/2 125/21/2 153/58/2
f 155/55/18 152/59/18 124/41/18
f 130/34/19 156/54/19 151/61/19
f 131/10/20 120/11/20 150/62/20
f 134/25/21 158/84/21 146/56/21
f 159/47/14 149/63/14 115/3/14
f 115/3/22 149/63/22 213/64/22
f 214/66/23 147/48/23 111/65/23
f 162/15/2 165/68/2 164/67/2
f 165/68/14 162/15/14 112/7/14
f 163/14/15 164/67/15 160/13/15
f 164/67/3 165/68/3 161/8/3
f 166/69/2 167/70/2 169/52/2
f 157/51/25 169/52/25 167/70/25
f 167/70/16 166/69/16 125/21/16
f 125/21/27 166/69/27 168/53/27
f 216/71/55 218/78/55 176/72/55
f 135/45/44 172/46/44 170/73/44
f 118/60/44 171/76/44 173/74/44
f 210/75/44 215/109/44 171/76/44
f 217/77/44 174/79/44 176/72/44
f 176/72/56 174/79/56 170/73/56
f 171/76/57 175/81/57 177/80/57
f 217/77/58 175/81/58 171/76/58
f 185/83/33 184/82/33 180/49/33
f 134/25/15 179/86/15 181/50/15
f 180/49/15 178/85/15 114/5/15
f 178/85/15 179/86/15 134/25/15
f 189/90/15 188/87/15 184/82/15
f 183/88/17 185/83/17 181/50/17
f 180/49/2 184/82/2 182/89/2
f 182/89/32 183/88/32 179/86/32
f 189/90/24 193/95/24 192/91/24
f 187/92/15 189/90/15 185/83/15
f 184/82/15 188/87/15 186/93/15
f 186/93/15 187/92/15 183/88/15
f 192/91/15 193/95/15 191/94/15
f 191/94/2 193/95/2 189/90/2
f 192/91/17 190/96/17 186/93/17
f 186/93/3 190/96/3 191/94/3
f 197/98/54 196/97/54 144/43/54
f 144/43/53 196/97/53 195/99/53
f 143/44/52 195/99/52 194/100/52
f 194/100/51 197/98/51 141/26/51
f 208/102/59 209/101/59 201/31/59
f 199/35/60 207/103/60 208/102/60
f 198/36/61 206/104/61 207/103/61
f 209/101/62 206/104/62 198/36/62
f 209/101/54 208/102/54 204/105/54
f 204/105/53 208/102/53 207/103/53
f 203/106/52 207/103/52 206/104/52
f 206/104/51 209/101/51 205/108/51
f 202/107/63 205/108/63 197/98/63
f 195/99/64 203/106/64 202/107/64
f 196/97/65 204/105/65 203/106/65
f 205/108/66 204/105/66 196/97/66
f 174/79/67 217/77/67 215/109/67
f 175/81/44 217/77/44 218/78/44
f 170/73/44 215/109/44 210/75/44
f 173/74/68 177/80/68 218/78/68
f 151/61/23 214/66/23 210/75/23
f 173/74/44 216/71/44 212/1/44
f 139/42/44 212/1/44 211/2/44
f 26/45/1 103/1/1 6/3/1
f 3/7/2 20/4/2 4/6/2
f 45/57/2 20/4/2 52/8/2
f 30/42/3 36/9/3 11/11/3
f 5/5/2 39/12/2 4/6/2
f 3/7/4 4/6/4 53/15/4
f 10/20/5 14/16/5 12/18/5
f 7/30/6 18/19/6 10/20/6
f 33/39/3 20/4/3 31/22/3
f 13/17/7 17/23/7 12/18/7
f 33/39/4 25/25/4 29/27/4
f 7/30/4 10/20/4 8/24/4
f 19/29/69 1/28/69 17/23/69
f 33/39/4 19/29/4 13/17/4
f 1/28/70 25/25/70 18/19/70
f 17/23/9 18/19/9 8/24/9
f 89/36/10 92/31/10 28/33/10
f 31/22/3 16/21/3 36/9/3
f 15/41/3 31/22/3 21/34/3
f 24/38/11 90/35/11 28/33/11
f 23/40/12 91/37/12 24/38/12
f 25/25/4 33/39/4 14/16/4
f 27/32/4 23/40/4 28/33/4
f 19/29/3 33/39/3 15/41/3
f 9/60/3 21/34/3 30/42/3
f 25/25/4 5/5/4 32/26/4
f 35/43/4 5/5/4 34/44/4
f 20/4/4 33/39/4 34/44/4
f 92/31/13 91/37/13 27/32/13
f 107/71/1 103/1/1 63/46/1
f 2/65/14 26/45/14 38/48/14
f 49/84/15 39/12/15 72/50/15
f 44/58/16 48/51/16 59/53/16
f 43/59/17 15/41/17 47/54/17
f 1/28/17 19/29/17 37/56/17
f 51/13/2 39/12/2 52/8/2
f 16/21/2 20/4/2 44/58/2
f 46/55/18 19/29/18 43/59/18
f 21/34/19 9/60/19 47/54/19
f 11/11/20 22/10/20 41/62/20
f 49/84/21 25/25/21 37/56/21
f 26/45/14 6/3/14 50/47/14
f 102/2/22 104/64/22 6/3/22
f 101/75/23 2/65/23 105/66/23
f 54/14/2 55/67/2 53/15/2
f 52/8/14 3/7/14 56/68/14
f 4/6/15 51/13/15 54/14/15
f 51/13/24 52/8/24 55/67/24
f 58/70/2 57/69/2 60/52/2
f 60/52/25 48/51/25 58/70/25
f 22/10/26 16/21/26 58/70/26
f 57/69/27 16/21/27 59/53/27
f 109/78/71 107/71/71 67/72/71
f 63/46/1 26/45/1 61/73/1
f 62/76/1 9/60/1 64/74/1
f 106/109/1 101/75/1 62/76/1
f 65/79/1 108/77/1 67/72/1
f 63/46/29 61/73/29 67/72/29
f 66/81/30 62/76/30 68/80/30
f 106/109/72 62/76/72 108/77/72
f 72/50/32 71/49/32 76/83/32
f 70/86/15 25/25/15 72/50/15
f 39/12/15 5/5/15 71/49/15
f 5/5/15 25/25/15 69/85/15
f 80/90/15 76/83/15 79/87/15
f 70/86/17 72/50/17 74/88/17
f 75/82/2 71/49/2 73/89/2
f 69/85/33 70/86/33 73/89/33
f 84/95/3 80/90/3 83/91/3
f 74/88/15 76/83/15 78/92/15
f 79/87/15 75/82/15 77/93/15
f 73/89/15 74/88/15 77/93/15
f 81/96/15 82/94/15 83/91/15
f 78/92/2 80/90/2 82/94/2
f 79/87/17 77/93/17 83/91/17
f 81/96/24 77/93/24 82/94/24
f 32/26/13 35/43/13 88/98/13
f 87/97/12 35/43/12 86/99/12
f 86/99/11 34/44/11 85/100/11
f 29/27/10 32/26/10 85/100/10
f 91/37/34 92/31/34 99/102/34
f 98/103/35 90/35/35 99/102/35
f 97/104/36 89/36/36 98/103/36
f 92/31/37 89/36/37 100/101/37
f 96/108/13 95/105/13 100/101/13
f 99/102/12 95/105/12 98/103/12
f 98/103/11 94/106/11 97/104/11
f 93/107/10 96/108/10 97/104/10
f 85/100/38 88/98/38 93/107/38
f 94/106/39 86/99/39 93/107/39
f 95/105/40 87/97/40 94/106/40
f 88/98/41 87/97/41 96/108/41
f 61/73/73 106/109/73 65/79/73
f 108/77/1 66/81/1 109/78/1
f 2/65/1 101/75/1 61/73/1
f 68/80/74 64/74/74 109/78/74
f 9/60/23 101/75/23 42/61/23
f 30/42/1 103/1/1 64/74/1
f 103/1/1 30/42/1 102/2/1
f 211/2/44 212/1/44 115/3/44
f 114/5/2 129/4/2 113/6/2
f 154/57/2 161/8/2 129/4/2
f 131/10/24 145/9/24 120/11/24
f 114/5/2 113/6/2 148/12/2
f 112/7/45 162/15/45 113/6/45
f 122/17/46 123/16/46 121/18/46
f 123/16/47 127/19/47 119/20/47
f 142/39/24 140/22/24 129/4/24
f 122/17/48 121/18/48 126/23/48
f 142/39/45 138/27/45 134/25/45
f 116/30/45 117/24/45 119/20/45
f 128/29/75 126/23/75 110/28/75
f 142/39/45 122/17/45 128/29/45
f 110/28/76 127/19/76 134/25/76
f 126/23/50 117/24/50 127/19/50
f 198/36/51 137/33/51 201/31/51
f 140/22/24 145/9/24 125/21/24
f 124/41/24 130/34/24 140/22/24
f 198/36/52 199/35/52 137/33/52
f 199/35/53 200/37/53 133/38/53
f 134/25/45 123/16/45 142/39/45
f 136/32/45 137/33/45 132/40/45
f 128/29/24 124/41/24 142/39/24
f 145/9/24 130/34/24 139/42/24
f 134/25/45 141/26/45 114/5/45
f 129/4/45 114/5/45 143/44/45
f 129/4/45 143/44/45 142/39/45
f 201/31/54 136/32/54 200/37/54
f 135/45/44 212/1/44 172/46/44
f 111/65/14 147/48/14 135/45/14
f 158/84/15 181/50/15 148/12/15
f 153/58/26 168/53/26 157/51/26
f 130/34/17 124/41/17 156/54/17
f 110/28/17 146/56/17 128/29/17
f 154/57/2 148/12/2 161/8/2
f 154/57/2 129/4/2 153/58/2
f 128/29/18 155/55/18 124/41/18
f 118/60/19 130/34/19 151/61/19
f 157/51/20 131/10/20 150/62/20
f 110/28/21 134/25/21 146/56/21
f 135/45/14 159/47/14 115/3/14
f 211/2/22 115/3/22 213/64/22
f 210/75/23 214/66/23 111/65/23
f 163/14/2 162/15/2 164/67/2
f 161/8/14 165/68/14 112/7/14
f 113/6/15 163/14/15 160/13/15
f 160/13/3 164/67/3 161/8/3
f 168/53/2 166/69/2 169/52/2
f 131/10/25 157/51/25 167/70/25
f 131/10/16 167/70/16 125/21/16
f 153/58/27 125/21/27 168/53/27
f 172/46/77 216/71/77 176/72/77
f 111/65/44 135/45/44 170/73/44
f 139/42/44 118/60/44 173/74/44
f 118/60/44 210/75/44 171/76/44
f 218/78/44 217/77/44 176/72/44
f 172/46/56 176/72/56 170/73/56
f 173/74/57 171/76/57 177/80/57
f 215/109/78 217/77/78 171/76/78
f 181/50/33 185/83/33 180/49/33
f 158/84/15 134/25/15 181/50/15
f 148/12/15 180/49/15 114/5/15
f 114/5/15 178/85/15 134/25/15
f 185/83/15 189/90/15 184/82/15
f 179/86/17 183/88/17 181/50/17
f 178/85/2 180/49/2 182/89/2
f 178/85/32 182/89/32 179/86/32
f 188/87/24 189/90/24 192/91/24
f 183/88/15 187/92/15 185/83/15
f 182/89/15 184/82/15 186/93/15
f 182/89/15 186/93/15 183/88/15
f 190/96/15 192/91/15 191/94/15
f 187/92/2 191/94/2 189/90/2
f 188/87/17 192/91/17 186/93/17
f 187/92/3 186/93/3 191/94/3
f 141/26/54 197/98/54 144/43/54
f 143/44/53 144/43/53 195/99/53
f 138/27/52 143/44/52 194/100/52
f 138/27/51 194/100/51 141/26/51
f 200/37/59 208/102/59 201/31/59
f 200/37/60 199/35/60 208/102/60
f 199/35/61 198/36/61 207/103/61
f 201/31/79 209/101/79 198/36/79
f 205/108/54 209/101/54 204/105/54
f 203/106/53 204/105/53 207/103/53
f 202/107/52 203/106/52 206/104/52
f 202/107/51 206/104/51 205/108/51
f 194/100/63 202/107/63 197/98/63
f 194/100/64 195/99/64 202/107/64
f 195/99/65 196/97/65 203/106/65
f 197/98/66 205/108/66 196/97/66
f 170/73/80 174/79/80 215/109/80
f 177/80/44 175/81/44 218/78/44
f 111/65/44 170/73/44 210/75/44
f 216/71/81 173/74/81 218/78/81
f 118/60/23 151/61/23 210/75/23
f 139/42/44 173/74/44 212/1/44
f 120/11/44 139/42/44 211/2/44
usemtl Material.002
f 41/62/82 104/64/82 102/2/82
f 211/2/82 213/64/82 150/62/82
f 11/11/82 41/62/82 102/2/82
f 120/11/82 211/2/82 150/62/82

View File

@@ -0,0 +1,30 @@
# 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
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
usemtl white

View File

@@ -1,5 +1,5 @@
sources = { sources = {
"test.cc", "loader_example.cc",
} }
-- premake4.lua -- premake4.lua
@@ -21,9 +21,9 @@ solution "TinyObjLoaderSolution"
configuration "Debug" configuration "Debug"
defines { "DEBUG" } -- -DDEBUG defines { "DEBUG" } -- -DDEBUG
flags { "Symbols" } flags { "Symbols" }
targetname "test_tinyobjloader_debug" targetname "loader_example_debug"
configuration "Release" configuration "Release"
-- defines { "NDEBUG" } -- -NDEBUG -- defines { "NDEBUG" } -- -NDEBUG
flags { "Symbols", "Optimize" } flags { "Symbols", "Optimize" }
targetname "test_tinyobjloader" targetname "loader_example"

2
python/TODO.md Normal file
View File

@@ -0,0 +1,2 @@
* PBR material
* Define index_t struct

View File

@@ -1,160 +1,206 @@
//python3 module for tinyobjloader // python2/3 module for tinyobjloader
// //
//usage: // usage:
// import tinyobjloader as tol // import tinyobjloader as tol
// model = tol.LoadObj(name) // model = tol.LoadObj(name)
// print(model["shapes"]) // print(model["shapes"])
// print(model["materials"] // print(model["materials"]
// note:
// `shape.mesh.index_t` is represented as flattened array: (vertex_index, normal_index, texcoord_index) * num_faces
#include <Python.h> #include <Python.h>
#include <vector> #include <vector>
#include "../tiny_obj_loader.h" #include "../tiny_obj_loader.h"
typedef std::vector<double> vectd; typedef std::vector<double> vectd;
typedef std::vector<int> vecti;
PyObject* PyObject* pyTupleFromfloat3(float array[3]) {
pyTupleFromfloat3 (float array[3]) int i;
{ PyObject* tuple = PyTuple_New(3);
int i;
PyObject* tuple = PyTuple_New(3);
for(i=0; i<=2 ; i++){ for (i = 0; i <= 2; i++) {
PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i])); PyTuple_SetItem(tuple, i, PyFloat_FromDouble(array[i]));
} }
return tuple; return tuple;
} }
extern "C" extern "C" {
{
static PyObject* static PyObject* pyLoadObj(PyObject* self, PyObject* args) {
pyLoadObj(PyObject* self, PyObject* args) PyObject *rtndict, *pyshapes, *pymaterials, *pymaterial_indices, *attribobj, *current, *meshobj;
{
PyObject *rtndict, *pyshapes, *pymaterials,
*current, *meshobj;
char const* filename; char const* current_name;
char *current_name; char const* filename;
vectd vect; vectd vect;
std::vector<tinyobj::index_t> indices;
std::vector<unsigned char> face_verts;
std::vector<tinyobj::shape_t> shapes; tinyobj::attrib_t attrib;
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
if(!PyArg_ParseTuple(args, "s", &filename)) if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
return NULL;
std::string err; std::string err;
tinyobj::LoadObj(shapes, materials, err, filename); tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename);
pyshapes = PyDict_New(); pyshapes = PyDict_New();
pymaterials = PyDict_New(); pymaterials = PyDict_New();
rtndict = PyDict_New(); pymaterial_indices = PyList_New(0);
rtndict = PyDict_New();
for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin() ; attribobj = PyDict_New();
shape != shapes.end(); shape++)
{
meshobj = PyDict_New();
tinyobj::mesh_t cm = (*shape).mesh;
for (int i = 0; i <= 4; i++ ) for (int i = 0; i <= 2; i++) {
{ current = PyList_New(0);
current = PyList_New(0);
switch(i) { switch (i) {
case 0:
case 0: current_name = "vertices";
current_name = "positions"; vect = vectd(attrib.vertices.begin(), attrib.vertices.end());
vect = vectd(cm.positions.begin(), cm.positions.end()); break; break;
case 1: case 1:
current_name = "normals"; current_name = "normals";
vect = vectd(cm.normals.begin(), cm.normals.end()); break; vect = vectd(attrib.normals.begin(), attrib.normals.end());
case 2: break;
current_name = "texcoords"; case 2:
vect = vectd(cm.texcoords.begin(), cm.texcoords.end()); break; current_name = "texcoords";
case 3: vect = vectd(attrib.texcoords.begin(), attrib.texcoords.end());
current_name = "indicies"; break;
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() ; for (vectd::iterator it = vect.begin(); it != vect.end(); it++) {
mat != materials.end(); mat++) PyList_Insert(current, it - vect.begin(), PyFloat_FromDouble(*it));
{
PyObject *matobj = PyDict_New();
PyObject *unknown_parameter = PyDict_New();
for (std::map<std::string, std::string>::iterator p = (*mat).unknown_parameter.begin() ;
p != (*mat).unknown_parameter.end(); ++p)
{
PyDict_SetItemString(unknown_parameter, p->first.c_str(), PyUnicode_FromString(p->second.c_str()));
}
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, "specular_highlight_texname", PyUnicode_FromString((*mat).specular_highlight_texname.c_str()));
PyDict_SetItemString(matobj, "bump_texname", PyUnicode_FromString((*mat).bump_texname.c_str()));
PyDict_SetItemString(matobj, "displacement_texname", PyUnicode_FromString((*mat).displacement_texname.c_str()));
PyDict_SetItemString(matobj, "alpha_texname", PyUnicode_FromString((*mat).alpha_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(matobj, "unknown_parameter", unknown_parameter);
PyDict_SetItemString(pymaterials, (*mat).name.c_str(), matobj);
} }
PyDict_SetItemString(rtndict, "shapes", pyshapes); PyDict_SetItemString(attribobj, current_name, current);
PyDict_SetItemString(rtndict, "materials", pymaterials); }
return rtndict; for (std::vector<tinyobj::shape_t>::iterator shape = shapes.begin();
shape != shapes.end(); shape++) {
meshobj = PyDict_New();
tinyobj::mesh_t cm = (*shape).mesh;
{
current = PyList_New(0);
for (size_t i = 0; i < cm.indices.size(); i++) {
// Flatten index array: v_idx, vn_idx, vt_idx, v_idx, vn_idx, vt_idx,
// ...
PyList_Insert(current, 3 * i + 0,
PyLong_FromLong(cm.indices[i].vertex_index));
PyList_Insert(current, 3 * i + 1,
PyLong_FromLong(cm.indices[i].normal_index));
PyList_Insert(current, 3 * i + 2,
PyLong_FromLong(cm.indices[i].texcoord_index));
}
PyDict_SetItemString(meshobj, "indices", current);
}
{
current = PyList_New(0);
for (size_t i = 0; i < cm.num_face_vertices.size(); i++) {
// Widen data type to long.
PyList_Insert(current, i, PyLong_FromLong(cm.num_face_vertices[i]));
}
PyDict_SetItemString(meshobj, "num_face_vertices", current);
}
{
current = PyList_New(0);
for (size_t i = 0; i < cm.material_ids.size(); i++) {
PyList_Insert(current, i, PyLong_FromLong(cm.material_ids[i]));
}
PyDict_SetItemString(meshobj, "material_ids", 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();
PyObject* unknown_parameter = PyDict_New();
for (std::map<std::string, std::string>::iterator p =
mat->unknown_parameter.begin();
p != mat->unknown_parameter.end(); ++p) {
PyDict_SetItemString(unknown_parameter, p->first.c_str(),
PyUnicode_FromString(p->second.c_str()));
}
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, "specular_highlight_texname",
PyUnicode_FromString(mat->specular_highlight_texname.c_str()));
PyDict_SetItemString(matobj, "bump_texname",
PyUnicode_FromString(mat->bump_texname.c_str()));
PyDict_SetItemString(
matobj, "displacement_texname",
PyUnicode_FromString(mat->displacement_texname.c_str()));
PyDict_SetItemString(matobj, "alpha_texname",
PyUnicode_FromString(mat->alpha_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(matobj, "unknown_parameter", unknown_parameter);
PyDict_SetItemString(pymaterials, mat->name.c_str(), matobj);
PyList_Append(pymaterial_indices, PyUnicode_FromString(mat->name.c_str()));
}
PyDict_SetItemString(rtndict, "shapes", pyshapes);
PyDict_SetItemString(rtndict, "materials", pymaterials);
PyDict_SetItemString(rtndict, "material_indices", pymaterial_indices);
PyDict_SetItemString(rtndict, "attribs", attribobj);
return rtndict;
} }
static PyMethodDef mMethods[] = { static PyMethodDef mMethods[] = {
{"LoadObj", pyLoadObj, METH_VARARGS}, {"LoadObj", pyLoadObj, METH_VARARGS}, {NULL, NULL, 0, NULL}
{NULL, NULL, 0, NULL}
}; };
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = { static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, "tinyobjloader",
PyModuleDef_HEAD_INIT, NULL, -1, mMethods};
"tinyobjloader",
NULL,
-1,
mMethods
};
PyMODINIT_FUNC PyInit_tinyobjloader(void) {
PyMODINIT_FUNC return PyModule_Create(&moduledef);
PyInit_tinyobjloader(void)
{
return PyModule_Create(&moduledef);
} }
#else
PyMODINIT_FUNC inittinyobjloader(void) {
Py_InitModule3("tinyobjloader", mMethods, NULL);
}
#endif // PY_MAJOR_VERSION >= 3
} }

279
test.cc
View File

@@ -1,279 +0,0 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <sstream>
#include <fstream>
static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool triangulate = true)
{
std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
if (triangulate)
{
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert((shapes[i].mesh.indices.size() % 3) == 0);
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
printf(" idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
}
} else {
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]);
}
printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
assert(shapes[i].mesh.material_ids.size() == shapes[i].mesh.num_vertices.size());
for (size_t m = 0; m < shapes[i].mesh.material_ids.size(); m++) {
printf(" material_id[%ld] = %d\n", m,
shapes[i].mesh.material_ids[m]);
}
}
printf("shape[%ld].num_faces: %ld\n", i, shapes[i].mesh.num_vertices.size());
for (size_t v = 0; v < shapes[i].mesh.num_vertices.size(); v++) {
printf(" num_vertices[%ld] = %ld\n", v,
static_cast<long>(shapes[i].mesh.num_vertices[v]));
}
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].num_tags: %ld\n", i, shapes[i].mesh.tags.size());
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
printf(" tag[%ld] = %s ", t, shapes[i].mesh.tags[t].name.c_str());
printf(" ints: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j)
{
printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
if (j < (shapes[i].mesh.tags[t].intValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf(" floats: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j)
{
printf("%f", shapes[i].mesh.tags[t].floatValues[j]);
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf(" strings: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j)
{
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
if (j < (shapes[i].mesh.tags[t].stringValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf("\n");
}
}
for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
printf(" material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
printf(" material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
printf(" material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
printf(" material.Ns = %f\n", materials[i].shininess);
printf(" material.Ni = %f\n", materials[i].ior);
printf(" material.dissolve = %f\n", materials[i].dissolve);
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
}
printf("\n");
}
}
static bool
TestLoadObj(
const char* filename,
const char* basepath = NULL,
unsigned int flags = 1 )
{
std::cout << "Loading " << filename << std::endl;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, filename, basepath, flags);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
printf("Failed to load/parse .obj.\n");
return false;
}
bool triangulate( ( flags & tinyobj::triangulation ) == tinyobj::triangulation );
PrintInfo(shapes, materials, triangulate );
return true;
}
static bool
TestStreamLoadObj()
{
std::cout << "Stream Loading " << std::endl;
std::stringstream objStream;
objStream
<< "mtllib cube.mtl\n"
"\n"
"v 0.000000 2.000000 2.000000\n"
"v 0.000000 0.000000 2.000000\n"
"v 2.000000 0.000000 2.000000\n"
"v 2.000000 2.000000 2.000000\n"
"v 0.000000 2.000000 0.000000\n"
"v 0.000000 0.000000 0.000000\n"
"v 2.000000 0.000000 0.000000\n"
"v 2.000000 2.000000 0.000000\n"
"# 8 vertices\n"
"\n"
"g front cube\n"
"usemtl white\n"
"f 1 2 3 4\n"
"g back cube\n"
"# expects white material\n"
"f 8 7 6 5\n"
"g right cube\n"
"usemtl red\n"
"f 4 3 7 8\n"
"g top cube\n"
"usemtl white\n"
"f 5 1 4 8\n"
"g left cube\n"
"usemtl green\n"
"f 5 6 2 1\n"
"g bottom cube\n"
"usemtl white\n"
"f 2 6 7 3\n"
"# 6 elements";
std::string matStream(
"newmtl white\n"
"Ka 0 0 0\n"
"Kd 1 1 1\n"
"Ks 0 0 0\n"
"\n"
"newmtl red\n"
"Ka 0 0 0\n"
"Kd 1 0 0\n"
"Ks 0 0 0\n"
"\n"
"newmtl green\n"
"Ka 0 0 0\n"
"Kd 0 1 0\n"
"Ks 0 0 0\n"
"\n"
"newmtl blue\n"
"Ka 0 0 0\n"
"Kd 0 0 1\n"
"Ks 0 0 0\n"
"\n"
"newmtl light\n"
"Ka 20 20 20\n"
"Kd 1 1 1\n"
"Ks 0 0 0");
using namespace tinyobj;
class MaterialStringStreamReader:
public MaterialReader
{
public:
MaterialStringStreamReader(const std::string& matSStream): m_matSStream(matSStream) {}
virtual ~MaterialStringStreamReader() {}
virtual bool operator() (
const std::string& matId,
std::vector<material_t>& materials,
std::map<std::string, int>& matMap,
std::string& err)
{
(void)matId;
(void)err;
LoadMtl(matMap, materials, m_matSStream);
return true;
}
private:
std::stringstream m_matSStream;
};
MaterialStringStreamReader matSSReader(matStream);
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, objStream, matSSReader);
if (!err.empty()) {
std::cerr << err << std::endl;
}
if (!ret) {
return false;
}
PrintInfo(shapes, materials);
return true;
}
int
main(
int argc,
char **argv)
{
if (argc > 1) {
const char* basepath = NULL;
if (argc > 2) {
basepath = argv[2];
}
assert(true == TestLoadObj(argv[1], basepath));
} else {
//assert(true == TestLoadObj("cornell_box.obj"));
//assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj());
assert(true == TestLoadObj("catmark_torus_creases0.obj", NULL, 0));
}
return 0;
}

16
tests/Makefile Normal file
View File

@@ -0,0 +1,16 @@
.PHONY: clean
CXX ?= g++
CXXFLAGS ?= -g -O2
tester: tester.cc
$(CXX) $(CXXFLAGS) -o tester tester.cc
all: tester
check: tester
./tester
clean:
rm -rf tester

37
tests/README.md Normal file
View File

@@ -0,0 +1,37 @@
# Build&Test
## Use makefile
$ make check
## Use ninja + kuroga
Assume
* ninja 1.4+
* python 2.6+
Are installed.
### Linux/MacOSX
$ python kuroga.py config-posix.py
$ ninja
### Windows
Visual Studio 2013 is required to build tester.
On Windows console.
> python kuroga.py config-msvc.py
> vcbuild.bat
Or on msys2 bash,
$ python kuroga.py config-msvc.py
$ cmd //c vcbuild.bat

10445
tests/catch.hpp Normal file

File diff suppressed because it is too large Load Diff

52
tests/config-msvc.py Normal file
View File

@@ -0,0 +1,52 @@
exe = "tester.exe"
toolchain = "msvc"
# optional
link_pool_depth = 1
# optional
builddir = {
"gnu" : "build"
, "msvc" : "build"
, "clang" : "build"
}
includes = {
"gnu" : [ "-I." ]
, "msvc" : [ "/I." ]
, "clang" : [ "-I." ]
}
defines = {
"gnu" : [ "-DEXAMPLE=1" ]
, "msvc" : [ "/DEXAMPLE=1" ]
, "clang" : [ "-DEXAMPLE=1" ]
}
cflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2" ]
, "clang" : [ "-O2", "-g" ]
}
cxxflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2", "/W4", "/EHsc"]
, "clang" : [ "-O2", "-g", "-fsanitize=address" ]
}
ldflags = {
"gnu" : [ ]
, "msvc" : [ ]
, "clang" : [ "-fsanitize=address" ]
}
# optionsl
cxx_files = [ "tester.cc" ]
c_files = [ ]
# You can register your own toolchain through register_toolchain function
def register_toolchain(ninja):
pass

53
tests/config-posix.py Normal file
View File

@@ -0,0 +1,53 @@
exe = "tester"
# "gnu" or "clang"
toolchain = "gnu"
# optional
link_pool_depth = 1
# optional
builddir = {
"gnu" : "build"
, "msvc" : "build"
, "clang" : "build"
}
includes = {
"gnu" : [ "-I." ]
, "msvc" : [ "/I." ]
, "clang" : [ "-I." ]
}
defines = {
"gnu" : [ ]
, "msvc" : [ ]
, "clang" : [ ]
}
cflags = {
"gnu" : [ "-O2", "-g" ]
, "msvc" : [ "/O2" ]
, "clang" : [ "-O2", "-g" ]
}
# Warn as much as possible: http://qiita.com/MitsutakaTakeda/items/6b9966f890cc9b944d75
cxxflags = {
"gnu" : [ "-O2", "-g", "-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused", "-fsanitize=address" ]
, "msvc" : [ "/O2", "/W4" ]
, "clang" : [ "-O2", "-g", "-Werror -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic", "-fsanitize=address" ]
}
ldflags = {
"gnu" : [ "-fsanitize=address" ]
, "msvc" : [ ]
, "clang" : [ "-fsanitize=address" ]
}
cxx_files = [ "tester.cc" ]
c_files = [ ]
# You can register your own toolchain through register_toolchain function
def register_toolchain(ninja):
pass

24
tests/issue-177.mtl Normal file
View File

@@ -0,0 +1,24 @@
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
newmtl red
Ka 0 0 0
Kd 1 0 0
Ks 0 0 0
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue
Ka 0 0 0
Kd 0 0 1
Ks 0 0 0
newmtl light
Ka 20 20 20
Kd 1 1 1
Ks 0 0 0

31
tests/issue-177.obj Normal file
View File

@@ -0,0 +1,31 @@
mtllib issue-177.mtl
v 0.000000 2.000000 2.000000
v 0.000000 0.000000 2.000000
v 2.000000 0.000000 2.000000
v 2.000000 2.000000 2.000000
v 0.000000 2.000000 0.000000
v 0.000000 0.000000 0.000000
v 2.000000 0.000000 0.000000
v 2.000000 2.000000 0.000000
# 8 vertices
g front cube
usemtl white
f 1 2 3 4
g back cube
# expects white material
f 8 7 6 5
g right cube
usemtl red
f 4 3 7 8
g top cube
usemtl white
f 5 1 4 8
g left cube
usemtl green
f 5 6 2 1
g bottom cube
usemtl white
f 2 6 7 3
# 6 elements

312
tests/kuroga.py Executable file
View File

@@ -0,0 +1,312 @@
#!/usr/bin/env python
#
# Kuroga, single python file meta-build system for ninja
# https://github.com/lighttransport/kuroga
#
# Requirements: python 2.6 or 2.7
#
# Usage: $ python kuroga.py input.py
#
import imp
import re
import textwrap
import glob
import os
import sys
# gcc preset
def add_gnu_rule(ninja):
ninja.rule('gnucxx', description='CXX $out',
command='$gnucxx -MMD -MF $out.d $gnudefines $gnuincludes $gnucxxflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('gnucc', description='CC $out',
command='$gnucc -MMD -MF $out.d $gnudefines $gnuincludes $gnucflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('gnulink', description='LINK $out', pool='link_pool',
command='$gnuld -o $out $in $libs $gnuldflags')
ninja.rule('gnuar', description='AR $out', pool='link_pool',
command='$gnuar rsc $out $in')
ninja.rule('gnustamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('gnucxx', 'g++')
ninja.variable('gnucc', 'gcc')
ninja.variable('gnuld', '$gnucxx')
ninja.variable('gnuar', 'ar')
ninja.newline()
# clang preset
def add_clang_rule(ninja):
ninja.rule('clangcxx', description='CXX $out',
command='$clangcxx -MMD -MF $out.d $clangdefines $clangincludes $clangcxxflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('clangcc', description='CC $out',
command='$clangcc -MMD -MF $out.d $clangdefines $clangincludes $clangcflags -c $in -o $out',
depfile='$out.d', deps='gcc')
ninja.rule('clanglink', description='LINK $out', pool='link_pool',
command='$clangld -o $out $in $libs $clangldflags')
ninja.rule('clangar', description='AR $out', pool='link_pool',
command='$clangar rsc $out $in')
ninja.rule('clangstamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('clangcxx', 'clang++')
ninja.variable('clangcc', 'clang')
ninja.variable('clangld', '$clangcxx')
ninja.variable('clangar', 'ar')
ninja.newline()
# msvc preset
def add_msvc_rule(ninja):
ninja.rule('msvccxx', description='CXX $out',
command='$msvccxx /TP /showIncludes $msvcdefines $msvcincludes $msvccxxflags -c $in /Fo$out',
depfile='$out.d', deps='msvc')
ninja.rule('msvccc', description='CC $out',
command='$msvccc /TC /showIncludes $msvcdefines $msvcincludes $msvccflags -c $in /Fo$out',
depfile='$out.d', deps='msvc')
ninja.rule('msvclink', description='LINK $out', pool='link_pool',
command='$msvcld $msvcldflags $in $libs /OUT:$out')
ninja.rule('msvcar', description='AR $out', pool='link_pool',
command='$msvcar $in /OUT:$out')
#ninja.rule('msvcstamp', description='STAMP $out', command='touch $out')
ninja.newline()
ninja.variable('msvccxx', 'cl.exe')
ninja.variable('msvccc', 'cl.exe')
ninja.variable('msvcld', 'link.exe')
ninja.variable('msvcar', 'lib.exe')
ninja.newline()
# -- from ninja_syntax.py --
def escape_path(word):
return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:')
class Writer(object):
def __init__(self, output, width=78):
self.output = output
self.width = width
def newline(self):
self.output.write('\n')
def comment(self, text, has_path=False):
for line in textwrap.wrap(text, self.width - 2, break_long_words=False,
break_on_hyphens=False):
self.output.write('# ' + line + '\n')
def variable(self, key, value, indent=0):
if value is None:
return
if isinstance(value, list):
value = ' '.join(filter(None, value)) # Filter out empty strings.
self._line('%s = %s' % (key, value), indent)
def pool(self, name, depth):
self._line('pool %s' % name)
self.variable('depth', depth, indent=1)
def rule(self, name, command, description=None, depfile=None,
generator=False, pool=None, restat=False, rspfile=None,
rspfile_content=None, deps=None):
self._line('rule %s' % name)
self.variable('command', command, indent=1)
if description:
self.variable('description', description, indent=1)
if depfile:
self.variable('depfile', depfile, indent=1)
if generator:
self.variable('generator', '1', indent=1)
if pool:
self.variable('pool', pool, indent=1)
if restat:
self.variable('restat', '1', indent=1)
if rspfile:
self.variable('rspfile', rspfile, indent=1)
if rspfile_content:
self.variable('rspfile_content', rspfile_content, indent=1)
if deps:
self.variable('deps', deps, indent=1)
def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
variables=None):
outputs = as_list(outputs)
out_outputs = [escape_path(x) for x in outputs]
all_inputs = [escape_path(x) for x in as_list(inputs)]
if implicit:
implicit = [escape_path(x) for x in as_list(implicit)]
all_inputs.append('|')
all_inputs.extend(implicit)
if order_only:
order_only = [escape_path(x) for x in as_list(order_only)]
all_inputs.append('||')
all_inputs.extend(order_only)
self._line('build %s: %s' % (' '.join(out_outputs),
' '.join([rule] + all_inputs)))
if variables:
if isinstance(variables, dict):
iterator = iter(variables.items())
else:
iterator = iter(variables)
for key, val in iterator:
self.variable(key, val, indent=1)
return outputs
def include(self, path):
self._line('include %s' % path)
def subninja(self, path):
self._line('subninja %s' % path)
def default(self, paths):
self._line('default %s' % ' '.join(as_list(paths)))
def _count_dollars_before_index(self, s, i):
"""Returns the number of '$' characters right in front of s[i]."""
dollar_count = 0
dollar_index = i - 1
while dollar_index > 0 and s[dollar_index] == '$':
dollar_count += 1
dollar_index -= 1
return dollar_count
def _line(self, text, indent=0):
"""Write 'text' word-wrapped at self.width characters."""
leading_space = ' ' * indent
while len(leading_space) + len(text) > self.width:
# The text is too wide; wrap if possible.
# Find the rightmost space that would obey our width constraint and
# that's not an escaped space.
available_space = self.width - len(leading_space) - len(' $')
space = available_space
while True:
space = text.rfind(' ', 0, space)
if (space < 0 or
self._count_dollars_before_index(text, space) % 2 == 0):
break
if space < 0:
# No such space; just use the first unescaped space we can find.
space = available_space - 1
while True:
space = text.find(' ', space + 1)
if (space < 0 or
self._count_dollars_before_index(text, space) % 2 == 0):
break
if space < 0:
# Give up on breaking.
break
self.output.write(leading_space + text[0:space] + ' $\n')
text = text[space+1:]
# Subsequent lines are continuations, so indent them.
leading_space = ' ' * (indent+2)
self.output.write(leading_space + text + '\n')
def close(self):
self.output.close()
def as_list(input):
if input is None:
return []
if isinstance(input, list):
return input
return [input]
# -- end from ninja_syntax.py --
def gen(ninja, toolchain, config):
ninja.variable('ninja_required_version', '1.4')
ninja.newline()
if hasattr(config, "builddir"):
builddir = config.builddir[toolchain]
ninja.variable(toolchain + 'builddir', builddir)
else:
builddir = ''
ninja.variable(toolchain + 'defines', config.defines[toolchain] or [])
ninja.variable(toolchain + 'includes', config.includes[toolchain] or [])
ninja.variable(toolchain + 'cflags', config.cflags[toolchain] or [])
ninja.variable(toolchain + 'cxxflags', config.cxxflags[toolchain] or [])
ninja.variable(toolchain + 'ldflags', config.ldflags[toolchain] or [])
ninja.newline()
if hasattr(config, "link_pool_depth"):
ninja.pool('link_pool', depth=config.link_pool_depth)
else:
ninja.pool('link_pool', depth=4)
ninja.newline()
# Add default toolchain(gnu, clang and msvc)
add_gnu_rule(ninja)
add_clang_rule(ninja)
add_msvc_rule(ninja)
obj_files = []
cc = toolchain + 'cc'
cxx = toolchain + 'cxx'
link = toolchain + 'link'
ar = toolchain + 'ar'
if hasattr(config, "cxx_files"):
for src in config.cxx_files:
srcfile = src
obj = os.path.splitext(srcfile)[0] + '.o'
obj = os.path.join(builddir, obj);
obj_files.append(obj)
ninja.build(obj, cxx, srcfile)
ninja.newline()
if hasattr(config, "c_files"):
for src in config.c_files:
srcfile = src
obj = os.path.splitext(srcfile)[0] + '.o'
obj = os.path.join(builddir, obj);
obj_files.append(obj)
ninja.build(obj, cc, srcfile)
ninja.newline()
targetlist = []
if hasattr(config, "exe"):
ninja.build(config.exe, link, obj_files)
targetlist.append(config.exe)
if hasattr(config, "staticlib"):
ninja.build(config.staticlib, ar, obj_files)
targetlist.append(config.staticlib)
ninja.build('all', 'phony', targetlist)
ninja.newline()
ninja.default('all')
def main():
if len(sys.argv) < 2:
print("Usage: python kuroga.py config.py")
sys.exit(1)
config = imp.load_source("config", sys.argv[1])
f = open('build.ninja', 'w')
ninja = Writer(f)
if hasattr(config, "register_toolchain"):
config.register_toolchain(ninja)
gen(ninja, config.toolchain, config)
f.close()
main()

Some files were not shown because too many files have changed in this diff Show More