Compare commits

...

156 Commits

Author SHA1 Message Date
Syoyo Fujita
125d8e50a9 fopen_s -> fopen in linux(posix) code path. 2019-11-09 20:52:56 +09:00
Syoyo Fujita
45cac78709 Fix utf8 filepath on MinGW based on PR 222. 2019-11-09 20:42:55 +09:00
Syoyo Fujita
a9d86c1af4 Add URL of Vulkan-Samples. 2019-11-08 14:45:16 +09:00
Syoyo Fujita
2f26eddac4 Merge pull request #220 from Selmar/doublesided_default_serialization
Doublesided default serialization
2019-11-01 13:39:36 +09:00
Selmar Kok
a0939550ca Merge branch 'master' of github.com:syoyo/tinygltf into doublesided_default_serialization 2019-10-31 15:10:03 +01:00
Selmar Kok
58ab95be2f only serialize doublesided if it is not the default value 2019-10-31 15:08:03 +01:00
Syoyo Fujita
bf0e4f8e45 Merge pull request #219 from syoyo/travis-gcc-4.8
Travis gcc 4.8
2019-10-31 19:34:33 +09:00
Syoyo Fujita
30f333c607 Fix travis script. 2019-10-31 02:17:22 +09:00
Syoyo Fujita
419162716e Introduce TINYGLTF_BUILD_EXAMPLES option to CMakeLists.txt. Fixes #218 2019-10-31 01:55:57 +09:00
Syoyo Fujita
9533c352a1 Add gcc-4.8 build on Travis. 2019-10-31 01:02:43 +09:00
Syoyo Fujita
9ff3d93084 Merge pull request #217 from syoyo/store-json-string-for-extras-and-extensions
Add feature to store original JSON string for extras and extensions
2019-10-30 19:08:08 +09:00
Syoyo Fujita
aea514a975 Merge pull request #216 from harokyang/feature/utf8_path
Feature/utf8 path
2019-10-30 17:40:22 +09:00
Harokyang
05a4456948 fix build error on C++11/C++14 2019-10-30 16:30:00 +08:00
Syoyo Fujita
6e08b17ce3 Add feature to store original JSON string for extras and extensions(for user-specific JSON parsing). # Fixes 215
Fix some glTF object(e.g. Skin) does not have extras and/or extensions property.
2019-10-30 17:25:38 +09:00
Harokyang
fb256609f2 support writing with utf-8 filepath 2019-10-30 16:14:10 +08:00
Harokyang
5cecef2b92 Treat all filepath string as utf-8 encoded
On Windows, convert utf-8 to wchar string before interact with filepath
2019-10-30 15:17:09 +08:00
Syoyo Fujita
1100f0f1eb Allow parsing integer number value as double(For example, glTF-Sample-Models/2.0/Cameras/glTF has zfar number property with integer value, which trigerred a parsing failure). 2019-10-30 15:18:55 +09:00
Syoyo Fujita
2b66c81f67 Merge pull request #212 from Selmar/move_operator
Move semantics
2019-10-30 15:11:26 +09:00
Selmar Kok
f29375f59b revert some local modifications, oops.... >_> 2019-10-29 16:25:37 +01:00
Selmar Kok
79e3df26a8 replace TINYGLTF_USE_NO_EXCEPT with GNU compiler version check 2019-10-29 16:22:07 +01:00
Selmar Kok
e3cf5edb94 Merge remote-tracking branch 'origin/Selmar-move_operator' into move_operator 2019-10-29 16:09:40 +01:00
Selmar Kok
b74fadef8e TINYGLTF_USE_NOEXCEPT 2019-10-29 16:09:32 +01:00
Syoyo Fujita
a11709a9ff Merge pull request #213 from dmuir/master
Validate model_length against length in LoadBinaryFromMemory.
2019-10-29 02:20:31 +09:00
Doug Muir
cf668683f9 Fix check for invalid glTF to consider invalid length/model_length combinations. 2019-10-28 09:51:13 -07:00
Syoyo Fujita
817bbcfb58 Show clang version in Travis build. 2019-10-23 00:41:40 +09:00
Selmar Kok
23467959ca pbrMetallicRoughnes default noexcept move operator 2019-10-21 19:23:15 +02:00
Selmar Kok
6f08785e9f Merge remote-tracking branch 'origin/master' into move_operator 2019-10-21 17:58:57 +02:00
Selmar Kok
ff2b1f92dd use default noexcept move constructor / operator 2019-10-21 17:58:09 +02:00
Syoyo Fujita
e886247329 Fix parsing a glTF file with 2GB+ or lareger size. 2019-10-20 17:47:50 +09:00
Syoyo Fujita
83bb1a48d7 Merge pull request #211 from Selmar/add_missing_serialization
small serialization additions
2019-10-19 15:18:19 +09:00
Selmar Kok
c3353e1acd set default values for baseColorFactor so that it has correct values when parsing a material without a pbrMetallicRoughness struct 2019-10-18 18:22:35 +02:00
Selmar Kok
81b672bcc2 add some missing serialization // add mesh==() weights comparison // use const iterator for extension serialization 2019-10-18 16:08:44 +02:00
Syoyo Fujita
cece6ee6d2 Merge pull request #209 from patriciogonzalezvivo/master
Adding glslViewer
2019-10-08 19:21:51 +09:00
Patricio Gonzalez Vivo
31f875ddbc adding glslViewer 2019-10-08 03:07:58 -07:00
Syoyo Fujita
8dccf9bf4e Merge pull request #208 from toshiks/patch-1
Added project to Readme.md (QuickLook GLTF plugin)
2019-09-15 14:50:06 +09:00
Anton Klochkov
508dcfa2e6 Added project to Readme.md (QuickLook GLTF plugin) 2019-09-15 01:25:47 +03:00
Syoyo Fujita
7e009041e3 Do not serialize pbrMetallicRoughness when they have all default values. Fixes #204 2019-09-13 15:32:22 +09:00
Syoyo Fujita
14977937c2 Add a link to Lighthouse 2. 2019-09-09 20:07:54 +09:00
Syoyo Fujita
8bb18fbd9c Merge pull request #202 from Ybalrid/fix_copy_assignment_operator
Fix broken copy-assignment operators
2019-09-06 13:58:54 +09:00
Arthur Brainville (Ybalrid)
9eeaf20133 Fix copy-assignment operator
When manual move constructor are declared, C++ compilers deletes the
copy constructor and copy-assign operator.

Most of these structures recently got a move ctor added, and copy ctor
re-enabled ( = default ). But copy-assignment are missing, thus in some
context, breaking instantiations of templates like std::vector<>.
2019-09-05 13:02:05 +02:00
Syoyo Fujita
a34aa8ea77 Suppress variable-is-shadowed warnings.
Apply clang-format.
Add note on RapidJSON and C++14 compilation flags.
2019-09-05 14:40:32 +09:00
Syoyo Fujita
59b2966f81 Merge branch 'master' of https://github.com/jrkoonce/tinygltf into jrkoonce-master 2019-09-05 14:22:51 +09:00
jrkoonce
7481011fd9 Removing RapidJSON toggle 2019-09-04 13:46:59 -05:00
jrkoonce
0d2b6efa6f Removing warnings 2019-09-04 13:46:45 -05:00
jrkoonce
ce7fa7419b Support simultaneous gltf load/saves
Added support for RapidJSON's CrtAllocator which is stateless and allows multiple documents to be in use at once, removing that restriction on default documents.  Enable with TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
2019-09-04 13:31:44 -05:00
jrkoonce
906f98fa74 Revert "Support simultaneous gltf load/saves"
This reverts commit d2a2703ec5.
2019-09-04 13:30:02 -05:00
jrkoonce
d2a2703ec5 Support simultaneous gltf load/saves
Added support for RapidJSON's CrtAllocator which is stateless and allows multiple documents to be in use at once, removing that restriction on default documents.  Enable with TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
2019-09-04 12:19:27 -05:00
jrkoonce
95f05757d6 Revert "Support simultaneous gltf load/saves (TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR)"
This reverts commit ab63db6318.
2019-09-04 12:15:51 -05:00
jrkoonce
ab63db6318 Support simultaneous gltf load/saves (TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR)
This allows multiple gltf's to be loaded/saved in parallel.  It removes the restriction of a single JsonDocument active at once which is default behavior.  Enable with TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
2019-09-04 12:01:39 -05:00
jrkoonce
6ff95392b0 Fix Compiler Warnings 2019-09-04 10:50:55 -05:00
Syoyo Fujita
c29bd3d9ce Use const reference for Buffer to fix compilation.
Removed UTF BOM?
2019-09-04 14:26:58 +09:00
jrkoonce
63419a11e1 Revert accidental committed change
Put "JsonX" helpers back in anonymous namespace to keep them inside local translation unit.
2019-09-03 17:06:41 -05:00
jrkoonce
06c30c4d04 Fixed Bugs/Unit Tests Pass
Fixed bugs found by unit tests and got unit tests running with RapidJSON as well as nlohmann.
2019-09-03 15:56:48 -05:00
jrkoonce
67e6160a9a Fixed move bugs 2019-09-03 10:42:39 -05:00
jrkoonce
a3b8b355ae Merge branch 'pr/1' 2019-09-03 10:30:19 -05:00
jrkoonce
5145394239 Made C++14 optional, default off. 2019-09-03 09:48:30 -05:00
Syoyo Fujita
67aa2ca75e Merge pull request #200 from ux3d/feature/allow-scenes-without-nodes
allow scenes without nodes
2019-09-02 22:12:15 +09:00
Benjamin Schmithüsen
ce25385eab remove extra parenthesis 2019-09-02 13:43:24 +02:00
Benjamin Schmithüsen
6143c6662b don't fail if a scene has no nodes property (which is not required) 2019-09-02 13:41:59 +02:00
Syoyo Fujita
81d75df48a Rename typeSizeInBytes to numComponents. 2019-08-30 19:19:52 +09:00
DingboDingboDingbo
83ccb9f28d GetTypeSizeInBytes not returning Type Size In Bytes
Changed name to be less misleading.
2019-08-29 18:49:15 -04:00
jrkoonce
9b6f52e98a Fix bug in ParseNumberArrayProperty()
Only doubles were being accepted instead of any number (including ordinals)
2019-08-29 13:56:58 -05:00
jrkoonce
5cecc41db9 More cleanup
1. Reserve array memory when converting JSON to Value for heap efficiency.
2. Grouped more JSON abstraction functions together and put in anonymous namespace instead of making each static.
2019-08-29 11:45:04 -05:00
jrkoonce
208c3058bf Remove test code accidentally commited 2019-08-29 11:28:07 -05:00
jrkoonce
cba5d6caae RapidJson 1.1 support + More move semantics
*Support for RapidJson 1.1, use TINYGLTF_USE_RAPIDJSON to toggle between RapidJson and nlohmann

*Lot more move semantics enabled.  All parsing and serialization now move all json objects with far fewer copies
2019-08-29 11:26:22 -05:00
jrkoonce
d1e1472992 Update tiny_gltf.h
Add/Enable move semantics to most all structs/classes
2019-08-27 11:51:02 -05:00
Syoyo Fujita
ff51570c26 Apply clang format.
Remove `const static std::string` global variable.
2019-08-24 16:29:14 +09:00
Syoyo Fujita
a472a3fa0f Add Set/Get SerializeDefaultValues method(W.I.P.) 2019-08-21 14:23:00 +09:00
Syoyo Fujita
1f160d5b8f Merge pull request #195 from ux3d/fix/parse-int-as-double
(also) parse int as double
2019-08-20 19:33:20 +09:00
Syoyo Fujita
5150a46072 Merge branch 'master' of github.com:syoyo/tinygltf 2019-08-20 17:11:29 +09:00
Syoyo Fujita
cea69e37a5 Suppress clang warnings. 2019-08-20 17:10:30 +09:00
Syoyo Fujita
8b56c016ab Merge pull request #193 from Selmar/emissiveFactor_defaults
Emissive factor defaults
2019-08-20 13:13:12 +09:00
Benjamin Schmithüsen
c7e205be87 when parsing a number from an int, also set the 'real value' to the value 2019-08-19 16:16:43 +02:00
Selmar Kok
6dba6c6aac [emissiveFactor] correct default values 2019-08-19 11:23:31 +02:00
Selmar Kok
6df800d2b6 [emissiveFactor] fix inconsistency with baseColorFactor where default values were set only for baseColorFactor and not emissiveFactor 2019-08-19 11:05:28 +02:00
Syoyo Fujita
2f044e77f1 Merge pull request #191 from Selmar/animation_extension_properties
Animation extension properties
2019-08-17 01:09:34 +09:00
Selmar Kok
af5a5ef026 Merge branch 'master' of github.com:syoyo/tinygltf into animation_extension_properties 2019-08-16 17:54:14 +02:00
Syoyo Fujita
6591ba4461 Merge pull request #190 from ux3d/feature/parse-node-weights
parse/serialize node weights
2019-08-16 22:21:48 +09:00
Benjamin Schmithüsen
74c3c10121 serialize node weights 2019-08-16 14:24:26 +02:00
Benjamin Schmithüsen
ad63bf748b parse node weights 2019-08-16 14:19:27 +02:00
Selmar Kok
5d43cf8e64 Merge branch 'master' of github.com:syoyo/tinygltf 2019-08-16 14:08:31 +02:00
Selmar Kok
4e2988eebd add extension property for Animation and AnimationChannel 2019-08-16 14:08:08 +02:00
Syoyo Fujita
ee179b2cb6 Set default value of minFilter and magFilter in Sampler to -1(unset), since glTF 2.0 spec does not declare default values for it.
Fixes #186
2019-08-16 13:11:30 +09:00
Syoyo Fujita
4ebd6368fb Fix inequality of texture index check when serializing texture of material.
Texture info was written even if it have invalid index(-1). Fixes #189
2019-08-15 12:25:50 +09:00
Syoyo Fujita
67d3d2504d Merge pull request #188 from ux3d/fix/alphaMode
Fixed saving of alphaMode if not OPAQUE
2019-08-14 21:40:07 +09:00
Patrick Härtl
d9a468bbb4 Fixed saving of alphaMode if not OPAQUE
Removed duplicated code for alphaCutoff
2019-08-14 14:14:07 +02:00
Syoyo Fujita
c7bae71f7f Merge pull request #185 from DerouineauNicolas/endif
remove extra #endif in examples/basic app
2019-08-14 03:09:53 +09:00
nicolasDEROUINEAU
f93642c196 remove extra #endif in examples/basic app 2019-08-13 15:08:01 +02:00
Syoyo Fujita
f68d5e1f2a Merge pull request #182 from ux3d/textureinfo
[TextureInfo] fix default value checks for serialization
2019-07-26 01:29:23 +09:00
Benjamin Schmithüsen
1c84fc22a5 fix default value checks for serialization 2019-07-25 16:07:27 +02:00
Syoyo Fujita
150f243b1b Change the behavior of NUMBER value in Value class. NUMBER now reprents the value is either int or real(floating point). 2019-07-25 19:22:44 +09:00
Syoyo Fujita
0ee273fdfa Update README. Add note on tinygltf::Value for extensions. 2019-07-24 19:55:04 +09:00
Syoyo Fujita
046400b17f Now material is parsed as a struct with explicit parameter definitions.
Implement Material struct serialization.
2019-07-24 19:26:48 +09:00
Syoyo Fujita
89fd93f815 Introduce TextureInfo class(W.I.P.) 2019-07-23 22:37:06 +09:00
Syoyo Fujita
e940337796 Merge pull request #180 from ux3d/master
Explicitly use the correct constructor for empty object
2019-07-23 18:55:34 +09:00
Syoyo Fujita
1b5f476d95 Merge pull request #178 from rapidimages/feature/write-to-streams
Serialize to stream
2019-07-17 18:53:35 +09:00
Johan Bowald
52936a00e0 clang format 2019-07-17 09:06:45 +02:00
Benjamin Schmithüsen
f3ef880029 call json constructor explicitly 2019-07-16 17:07:45 +02:00
Johan Bowald
1af7c1d784 can write to streams 2019-07-16 15:56:18 +02:00
Benjamin Schmithüsen
c0b79afecc Merge pull request #2 from syoyo/master
update from original repository
2019-07-15 15:13:50 +02:00
Syoyo Fujita
c49461b7c2 Merge pull request #176 from ux3d/feature/update-lights
Feature: update lights
2019-07-10 21:20:12 +09:00
Benjamin Schmithüsen
051f4be2f1 serialize lights 2019-07-09 17:59:20 +02:00
Benjamin Schmithüsen
4557b6aa22 fix spot light parsingg 2019-07-09 16:55:55 +02:00
Benjamin Schmithüsen
b2d7d88dbc parse additional light properties and fix defaults 2019-07-09 16:32:42 +02:00
Benjamin Schmithüsen
b7ca7c9381 update lights to follow the KHR_lights_punctual extension 2019-07-08 18:04:24 +02:00
Benjamin Schmithüsen
0ffedcbe79 Merge pull request #1 from syoyo/master
update fork
2019-07-08 17:40:20 +02:00
Syoyo Fujita
80faac5238 Merge pull request #174 from Ybalrid/pr_material_param_tex_info
Add Parameter::TextureStrength(). Precise default values.
2019-07-05 14:11:15 +09:00
Arthur Brianville (Ybalrid)
2a9d9deb67 Applied clang-format 2019-07-05 00:30:47 +02:00
Arthur Brainville
8a98d98cd9 Add Paramter::TextureStrength(). Precise default values.
The default values on these methods as been set to what is described [here](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0?ts=4#normaltextureinfo) and [here](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0?ts=4#occlusiontextureinfo).

This is to keep consistent with the API behavior from #144
2019-07-05 00:30:20 +02:00
Syoyo Fujita
689edcbef6 Merge pull request #173 from christophe-f8/master
Adding texture scale reading + asset copyright and texture names to the export
2019-07-04 15:39:22 +09:00
Christophe
820ede87db Adding texture scale reading (for normal maps) + asset copyright and texture names to the export 2019-07-04 15:21:21 +09:00
Syoyo Fujita
d6b0d0a61f Explicitly define copy constructor and copy assignment operator for Model an Node. 2019-06-29 17:31:13 +09:00
Syoyo Fujita
5f180aaf74 Merge pull request #171 from Ybalrid/fix_double_parse_material_name
Material names are stored once in material.name, then duplicated in "additionalValues"
2019-06-24 14:06:55 +09:00
Arthur Brainville (Ybalrid)
dab0daaedf Material names are stored once in material.name, then duplicated in "additionalValues"
This patch prevent this duplication
2019-06-23 21:50:10 +02:00
Syoyo Fujita
0ccc8dc262 Merge pull request #170 from Ybalrid/msvc_warn_fix
Fix C4267 warning (size_t -> int) convertion
2019-06-15 15:58:03 +09:00
Arthur Brainville (Ybalrid)
811e1d3899 Fix C4267 warning (size_t -> int) convertion 2019-06-15 07:32:38 +02:00
Syoyo Fujita
f65e06c5ca Merge pull request #169 from Ybalrid/remove_mesh_targets
Remove Mesh::targets, as targets only exists inside `Primitive`
2019-05-26 16:23:46 +09:00
Arthur Brianville (Ybalrid)
f29ae1a653 Remove Mesh::targets, as targets only exists inside Primitive 2019-05-25 22:30:55 +02:00
Syoyo Fujita
3bf16e4be5 Merge branch 'master' of github.com:syoyo/tinygltf 2019-05-16 16:55:09 +09:00
Syoyo Fujita
fbc4295770 Remove CATMULLROMSPLINE, which was removed in the final glTF 2.0 spec. 2019-05-16 16:54:28 +09:00
Syoyo Fujita
edf8d5cae1 Merge pull request #164 from DiligentGraphics/master
Updated readme: added link to Diligent Engine
2019-05-09 12:47:24 +09:00
DiligentGraphics
b7f2473225 Updated readme: added link to Diligent Engine 2019-05-08 18:33:26 -07:00
Syoyo Fujita
ed7bf66255 Merge pull request #162 from ux3d/master
add REQUIRE_VERSION to gltf validation and use it as default instead of REQUIRE_ALL
2019-05-03 15:08:36 +09:00
Syoyo Fujita
caa36dd050 Merge pull request #163 from jwmcglynn/fix-test-gltfs-standalone
Add "asset" section to BoundsChecking test models
2019-05-03 15:06:38 +09:00
Jeff McGlynn
389d5016ad Add "asset" section to BoundsChecking test models
These test assets were trimmed down and erroneously didn't have an
"asset" section or version number, which is required by the glTF spec.

This fixes test failures with pull request #162.
2019-05-02 23:05:13 -07:00
Benjamin Schmithüsen
d02ad0dede add REQUIRE_VERSION to gltf validation and use it as default instead of REQUIRE_ALL 2019-05-02 14:44:20 +02:00
Syoyo Fujita
8f67121deb Merge pull request #161 from rainliang000/patch-1
if image.uri empty, should use image.bufferView
2019-04-29 17:48:47 +09:00
rainliang000
62be8d04cf if image.uri empty, should use bufferview
if uri empty, shoud use mimeType and bufferview
2019-04-29 09:54:27 +08:00
Syoyo Fujita
d11a4c4d71 Merge pull request #160 from jwmcglynn/parse-integer
Parse integers directly instead of casting doubles
2019-04-27 14:57:54 +09:00
Jeff McGlynn
19b806e052 Parse integers directly instead of casting doubles
When parsing numeric values as doubles, its possible for users to
specify values that cannot be converted to integers, such as Inf, NaN,
and extremes such as 1e100.  If this value is received, and then cast to
an int, it is undefined behavior, which trips ubsan when running
tinygltf under a fuzzer.

Instead of parsing integral values as doubles, use nlohmann/json's
built-in support to parse integer and unsigned values directly, with
.is_number_integer() and .is_number_unsigned().

Add ParseIntegerProperty, ParseUnsignedProperty, and
ParseIntegerArrayProperty helpers that allow parsing directly to
int/uint values and update code to use them when appropriate.
2019-04-26 17:20:50 -07:00
Syoyo Fujita
e0ab69cb31 Merge pull request #158 from jwmcglynn/bounds-checking
Add checks for boundary conditions for malformed glTF files
2019-04-26 12:56:21 +09:00
Jeff McGlynn
8915252407 Add checks for boundary conditions for malformed glTF files
When loading untrusted glTF files, ideally an error should be returned
if the file is malformed instead of an exception/crash.  Add additional
validation for crashes found when running tinygltf under a fuzzer, and
add test cases to confirm:

1. Validate that the primitive indices value is within the
   model->accessors bounds before dereferencing.
2. Validate that the accessors bufferView index if valid.
3. Validate that the buffer's index is valid when parsing images.
4. For glb files, validate that the overall length is within the
   provided input buffer.
2019-04-25 16:51:09 -07:00
Jeff McGlynn
9446f65667 Set up tests to run in travis-ci and ignore test outputs in .gitignore 2019-04-25 16:26:26 -07:00
Syoyo Fujita
fb9f709166 Merge pull request #157 from Selmar/patch-1
correct Value::Equals mistake
2019-04-17 03:19:00 +09:00
Selmar
a63cc6373d correct Value::Equals mistake
a missing exclamation mark... ^^
2019-04-16 16:57:43 +02:00
Syoyo Fujita
b3c1471317 Merge pull request #155 from ffreling/accessor-normalized
Serialize accessor 'normalized' attribute.
2019-03-22 01:32:34 +09:00
Fabien Freling
9056aee823 Serialize accessor 'normalized' attribute. 2019-03-21 17:06:22 +01:00
Syoyo Fujita
29c431b2f2 Add build option with draco in Makefile. 2019-03-08 14:01:06 +09:00
Syoyo Fujita
d06b2c2022 Merge pull request #154 from Ybalrid/patch-3
Fix the display of the version history
2019-03-08 13:32:31 +09:00
Arthur Brainville
339c9d578a Fix the display of the version history
Markdown is like HTML: simple line-breaks don't work.

Besides, making a list with dots here looks nicer :)
2019-03-07 19:40:57 +01:00
Syoyo Fujita
7c315fa8a8 Merge pull request #153 from Ybalrid/patch-2
fix a few typos in README.md
2019-03-07 21:30:20 +09:00
Arthur Brainville
0f04ed018a fix a few typos in README.md 2019-03-07 13:23:59 +01:00
Syoyo Fujita
ca56f726d6 Merge branch '16bit-lodepng' 2019-03-07 21:04:25 +09:00
Syoyo Fujita
9cd14a461b Update README. 2019-03-07 01:05:02 +09:00
Syoyo Fujita
1ef603ea2a Merge pull request #150 from Ybalrid/sparse_accessor
Sparse accessor
2019-03-07 00:49:29 +09:00
Arthur Brainville (Ybalrid)
14d259f361 glview can now load static geometry modified by sparse accessor 2019-03-06 14:48:44 +00:00
Arthur Brainville (Ybalrid)
9223d3133a Ran clang-format on tiny_gltf.h 2019-03-06 14:00:56 +00:00
Arthur Brainville (Ybalrid)
9b321a8515 clang-format + added sparse accessor in loader_example 2019-03-06 12:39:39 +00:00
Arthur Brainville (Ybalrid)
7e9f734d73 Parse sparse accessors 2019-03-06 12:27:23 +00:00
Arthur Brainville (Ybalrid)
9d86405d3d Fix accessor ctor 2019-03-06 11:33:30 +00:00
Arthur Brainville (Ybalrid)
1ccb4ff580 added sparse structure to accessors 2019-03-06 11:30:00 +01:00
Syoyo Fujita
bf9c2f4abd Merge pull request #146 from WARP-LAB/master
Fix for when json and stb is aready used in project
2019-03-03 15:31:09 +09:00
kroko
fc0116b323 rename TINYGLTF_BYPASS_INCLUDE_x to TINYGLTF_NO_INCLUDE_x 2019-03-03 08:28:49 +02:00
kroko
606e5dde31 be more precise in readme about include bypassing flags 2019-03-03 01:56:34 +02:00
kroko
6a0d4c57b1 Fix for when json and stb is aready used in project v2 2019-03-03 01:28:45 +02:00
kroko
f4b6d11abc Fix for when json and stb is aready used in project 2019-03-03 01:11:31 +02:00
20 changed files with 5133 additions and 1853 deletions

1
.gitignore vendored
View File

@@ -67,4 +67,5 @@ imgui.ini
loader_example
tests/tester
tests/tester_noexcept
tests/issue-97.gltf

View File

@@ -31,6 +31,17 @@ matrix:
- addons: *1
compiler: clang
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
- addons: &3
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
compiler: gcc
env: COMPILER_VERSION=4.8 BUILD_TYPE=Debug
- addons: *3
compiler: gcc
env: COMPILER_VERSION=4.8 BUILD_TYPE=Release
before_install:
- ./.travis-before-install.sh
@@ -42,6 +53,11 @@ script:
- ${CC} -v
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
- ./loader_example ./models/Cube/Cube.gltf
- cd examples/raytrace
- cd tests
- clang++ -v
- make
- ./tester
- ./tester_noexcept
- cd ../examples/raytrace
- ../../premake5 gmake
- make

View File

@@ -4,14 +4,21 @@ PROJECT (tinygltf)
SET(CMAKE_CXX_STANDARD 11)
ADD_EXECUTABLE ( loader_example
loader_example.cc
)
option(TINYGLTF_BUILD_EXAMPLES "Build examples" ON)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
ADD_SUBDIRECTORY ( examples/validator )
if (TINYGLTF_BUILD_EXAMPLES)
ADD_EXECUTABLE ( loader_example
loader_example.cc
)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
ADD_SUBDIRECTORY ( examples/validator )
endif (TINYGLTF_BUILD_EXAMPLES)
#
# TinuGLTF is a header-only library, so no library build. just install header files.
#
INSTALL ( FILES
json.hpp
stb_image.h

View File

@@ -2,8 +2,12 @@
# Use this for strict compilation check(will work on clang 3.8+)
#EXTRA_CXXFLAGS := -fsanitize=address -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat
# With draco
# EXTRA_CXXFLAGS := -I../draco/src/ -I../draco/build -DTINYGLTF_ENABLE_DRACO -L../draco/build
# EXTRA_LINKFLAGS := -L../draco/build/ -ldracodec -ldraco
all:
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc
clang++ $(EXTRA_CXXFLAGS) -std=c++11 -g -O0 -o loader_example loader_example.cc $(EXTRA_LINKFLAGS)
lint:
deps/cpplint.py tiny_gltf.h

View File

@@ -7,9 +7,11 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
## Status
v2.2.0 release(Support loading 16bit PNG)
v2.1.0 release(Draco support)
v2.0.0 release(22 Aug, 2018)!
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
- v2.1.0 release(Draco support)
- v2.0.0 release(22 Aug, 2018)!
## Builds
@@ -45,13 +47,21 @@ v2.0.0 release(22 Aug, 2018)!
* [x] Load BMP
* [x] Load GIF
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
* Load from memory
* Morph traget
* [x] Sparse accessor
* Load glTF from memory
* Custom callback handler
* [x] Image load
* [x] Image save
* Extensions
* [x] Draco mesh decoding
## Note on extension property
In extension(`ExtensionMap`), JSON number value is parsed as int or float(number) and stored as `tinygltf::Value` object. If you want a floating point value from `tinygltf::Value`, use `GetNumberAsDouble()` method.
`IsNumber()` returns true if the underlying value is an int value or a floating point value.
## Examples
* [glview](examples/glview) : Simple glTF geometry viewer.
@@ -64,6 +74,11 @@ v2.0.0 release(22 Aug, 2018)!
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
* [TinyGltfImporter](http://doc.magnum.graphics/magnum/classMagnum_1_1Trade_1_1TinyGltfImporter.html) plugin for [Magnum](https://github.com/mosra/magnum), a lightweight and modular C++11/C++14 graphics middleware for games and data visualization.
* [Diligent Engine](https://github.com/DiligentGraphics/DiligentEngine) - A modern cross-platform low-level graphics library and rendering framework
* Lighthouse 2: a rendering framework for real-time ray tracing / path tracing experiments. https://github.com/jbikker/lighthouse2
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
* Your projects here! (Please send PR)
## TODOs
@@ -71,15 +86,13 @@ v2.0.0 release(22 Aug, 2018)!
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
* [ ] Mesh Compression/decompression(Open3DGC, etc)
* [x] Load Draco compressed mesh
* [x] Save Draco compressed mesh
* [ ] Save Draco compressed mesh
* [ ] Open3DGC?
* [ ] Support `extensions` and `extras` property
* [x] Support `extensions` and `extras` property
* [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR.
* [ ] 16bit PNG support in Serialization
* [ ] Write example and tests for `animation` and `skin`
* [ ] Skinning
* [ ] Morph targets
## Licenses
@@ -136,9 +149,15 @@ if (!ret) {
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option would be helpful if you do not want to load image files during glTF parsing.
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this featrure.
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
### Saving gltTF 2.0 model
* [ ] Buffers.
@@ -181,3 +200,4 @@ $ ./tester_noexcept
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
* stb_image : Public domain.
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
* RapidJSON : Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. http://rapidjson.org/

View File

@@ -1,365 +1,364 @@
#include <fstream>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>
#include "shaders.h"
#include "window.h"
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
#include "../../tiny_gltf.h"
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
bool loadModel(tinygltf::Model &model, const char *filename) {
tinygltf::TinyGLTF loader;
std::string err;
std::string warn;
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}
if (!err.empty()) {
std::cout << "ERR: " << err << std::endl;
}
if (!res)
std::cout << "Failed to load glTF: " << filename << std::endl;
else
std::cout << "Loaded glTF: " << filename << std::endl;
return res;
}
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
const tinygltf::BufferView &bufferView = model.bufferViews[i];
if (bufferView.target == 0) { // TODO impl drawarrays
std::cout << "WARN: bufferView.target is zero" << std::endl;
continue; // Unsupported bufferView.
/*
From spec2.0 readme:
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
... drawArrays function should be used with a count equal to
the count property of any of the accessors referenced by the
attributes property (they are all equal for a given
primitive).
*/
}
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
std::cout << "bufferview.target " << bufferView.target << std::endl;
GLuint vbo;
glGenBuffers(1, &vbo);
vbos[i] = vbo;
glBindBuffer(bufferView.target, vbo);
std::cout << "buffer.data.size = " << buffer.data.size()
<< ", bufferview.byteOffset = " << bufferView.byteOffset
<< std::endl;
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
}
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
for (auto &attrib : primitive.attributes) {
tinygltf::Accessor accessor = model.accessors[attrib.second];
int byteStride =
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
int size = 1;
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
size = accessor.type;
}
int vaa = -1;
if (attrib.first.compare("POSITION") == 0) vaa = 0;
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
if (vaa > -1) {
glEnableVertexAttribArray(vaa);
glVertexAttribPointer(vaa, size, accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, BUFFER_OFFSET(accessor.byteOffset));
} else
std::cout << "vaa missing: " << attrib.first << std::endl;
}
GLuint texid;
glGenTextures(1, &texid);
tinygltf::Texture &tex = model.textures[0];
tinygltf::Image &image = model.images[tex.source];
glBindTexture(GL_TEXTURE_2D, texid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GLenum format = GL_RGBA;
if (image.component == 1) {
format = GL_RED;
} else if (image.component == 2) {
format = GL_RG;
} else if (image.component == 3) {
format = GL_RGB;
} else {
// ???
}
GLenum type = GL_UNSIGNED_BYTE;
if (image.bits == 8) {
// ok
} else if (image.bits == 16) {
type = GL_UNSIGNED_SHORT;
} else {
// ???
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
format, type, &image.image.at(0));
}
return vbos;
}
// bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
}
}
GLuint bindModel(tinygltf::Model &model) {
std::map<int, GLuint> vbos;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
}
glBindVertexArray(0);
// cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) {
glDeleteBuffers(1, &vbos[i]);
}
return vao;
}
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
glDrawElements(primitive.mode, indexAccessor.count,
indexAccessor.componentType,
BUFFER_OFFSET(indexAccessor.byteOffset));
}
}
// recursively draw node and children nodes of model
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
drawMesh(model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) {
drawModelNodes(model, model.nodes[node.children[i]]);
}
}
void drawModel(GLuint vao, tinygltf::Model &model) {
glBindVertexArray(vao);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
drawModelNodes(model, model.nodes[scene.nodes[i]]);
}
glBindVertexArray(0);
}
void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) {
std::cout << "mesh : " << mesh.name << std::endl;
for (auto &primitive : mesh.primitives) {
const tinygltf::Accessor &indexAccessor =
model.accessors[primitive.indices];
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl;
tinygltf::Material &mat = model.materials[primitive.material];
for (auto &mats : mat.values) {
std::cout << "mat : " << mats.first.c_str() << std::endl;
}
for (auto &image : model.images) {
std::cout << "image name : " << image.uri << std::endl;
std::cout << " size : " << image.image.size() << std::endl;
std::cout << " w/h : " << image.width << "/" << image.height
<< std::endl;
}
std::cout << "indices : " << primitive.indices << std::endl;
std::cout << "mode : "
<< "(" << primitive.mode << ")" << std::endl;
for (auto &attrib : primitive.attributes) {
std::cout << "attribute : " << attrib.first.c_str() << std::endl;
}
}
}
}
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
// Camera matrix
glm::mat4 view = glm::lookAt(
pos, // Camera in World Space
lookat, // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
return view;
}
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
int h) {
glm::mat4 Projection =
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
// Or, for an ortho camera :
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
// // In world coordinates
glm::mat4 mvp = Projection * view_mat * model_mat;
return mvp;
}
void displayLoop(Window &window, const std::string &filename) {
Shaders shader = Shaders();
glUseProgram(shader.pid);
// grab uniforms to modify
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
tinygltf::Model model;
if (!loadModel(model, filename.c_str())) return;
GLuint vao = bindModel(model);
// dbgModel(model); return;
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
// generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
glm::vec3 sun_color = glm::vec3(1.0);
while (!window.Close()) {
window.Resize();
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glm::vec3(0, 1, 0)); // rotate model on y axis
model_mat = trans * model_rot;
// build a model-view-projection
GLint w, h;
glfwGetWindowSize(window.window, &w, &h);
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
glUniform3fv(sun_position_u, 1, &sun_position[0]);
glUniform3fv(sun_color_u, 1, &sun_color[0]);
drawModel(vao, model);
glfwSwapBuffers(window.window);
glfwPollEvents();
}
}
static void error_callback(int error, const char *description) {
(void)error;
fprintf(stderr, "Error: %s\n", description);
}
int main(int argc, char **argv) {
std::string filename = "../../models/Cube/Cube.gltf";
if (argc > 1) {
filename = argv[1];
}
glfwSetErrorCallback(error_callback);
if (!glfwInit()) return -1;
// Force create OpenGL 3.3
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
#endif
Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window);
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE;
#endif
glewInit();
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl;
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}
#include <fstream>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>
#include "shaders.h"
#include "window.h"
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
#include "../../tiny_gltf.h"
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
bool loadModel(tinygltf::Model &model, const char *filename) {
tinygltf::TinyGLTF loader;
std::string err;
std::string warn;
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
if (!warn.empty()) {
std::cout << "WARN: " << warn << std::endl;
}
if (!err.empty()) {
std::cout << "ERR: " << err << std::endl;
}
if (!res)
std::cout << "Failed to load glTF: " << filename << std::endl;
else
std::cout << "Loaded glTF: " << filename << std::endl;
return res;
}
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
const tinygltf::BufferView &bufferView = model.bufferViews[i];
if (bufferView.target == 0) { // TODO impl drawarrays
std::cout << "WARN: bufferView.target is zero" << std::endl;
continue; // Unsupported bufferView.
/*
From spec2.0 readme:
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
... drawArrays function should be used with a count equal to
the count property of any of the accessors referenced by the
attributes property (they are all equal for a given
primitive).
*/
}
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
std::cout << "bufferview.target " << bufferView.target << std::endl;
GLuint vbo;
glGenBuffers(1, &vbo);
vbos[i] = vbo;
glBindBuffer(bufferView.target, vbo);
std::cout << "buffer.data.size = " << buffer.data.size()
<< ", bufferview.byteOffset = " << bufferView.byteOffset
<< std::endl;
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
}
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
for (auto &attrib : primitive.attributes) {
tinygltf::Accessor accessor = model.accessors[attrib.second];
int byteStride =
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
int size = 1;
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
size = accessor.type;
}
int vaa = -1;
if (attrib.first.compare("POSITION") == 0) vaa = 0;
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
if (vaa > -1) {
glEnableVertexAttribArray(vaa);
glVertexAttribPointer(vaa, size, accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, BUFFER_OFFSET(accessor.byteOffset));
} else
std::cout << "vaa missing: " << attrib.first << std::endl;
}
GLuint texid;
glGenTextures(1, &texid);
tinygltf::Texture &tex = model.textures[0];
tinygltf::Image &image = model.images[tex.source];
glBindTexture(GL_TEXTURE_2D, texid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GLenum format = GL_RGBA;
if (image.component == 1) {
format = GL_RED;
} else if (image.component == 2) {
format = GL_RG;
} else if (image.component == 3) {
format = GL_RGB;
} else {
// ???
}
GLenum type = GL_UNSIGNED_BYTE;
if (image.bits == 8) {
// ok
} else if (image.bits == 16) {
type = GL_UNSIGNED_SHORT;
} else {
// ???
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
format, type, &image.image.at(0));
}
return vbos;
}
// bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
}
}
GLuint bindModel(tinygltf::Model &model) {
std::map<int, GLuint> vbos;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
}
glBindVertexArray(0);
// cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) {
glDeleteBuffers(1, &vbos[i]);
}
return vao;
}
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
glDrawElements(primitive.mode, indexAccessor.count,
indexAccessor.componentType,
BUFFER_OFFSET(indexAccessor.byteOffset));
}
}
// recursively draw node and children nodes of model
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
drawMesh(model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) {
drawModelNodes(model, model.nodes[node.children[i]]);
}
}
void drawModel(GLuint vao, tinygltf::Model &model) {
glBindVertexArray(vao);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
drawModelNodes(model, model.nodes[scene.nodes[i]]);
}
glBindVertexArray(0);
}
void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) {
std::cout << "mesh : " << mesh.name << std::endl;
for (auto &primitive : mesh.primitives) {
const tinygltf::Accessor &indexAccessor =
model.accessors[primitive.indices];
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl;
tinygltf::Material &mat = model.materials[primitive.material];
for (auto &mats : mat.values) {
std::cout << "mat : " << mats.first.c_str() << std::endl;
}
for (auto &image : model.images) {
std::cout << "image name : " << image.uri << std::endl;
std::cout << " size : " << image.image.size() << std::endl;
std::cout << " w/h : " << image.width << "/" << image.height
<< std::endl;
}
std::cout << "indices : " << primitive.indices << std::endl;
std::cout << "mode : "
<< "(" << primitive.mode << ")" << std::endl;
for (auto &attrib : primitive.attributes) {
std::cout << "attribute : " << attrib.first.c_str() << std::endl;
}
}
}
}
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
// Camera matrix
glm::mat4 view = glm::lookAt(
pos, // Camera in World Space
lookat, // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
return view;
}
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
int h) {
glm::mat4 Projection =
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
// Or, for an ortho camera :
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
// // In world coordinates
glm::mat4 mvp = Projection * view_mat * model_mat;
return mvp;
}
void displayLoop(Window &window, const std::string &filename) {
Shaders shader = Shaders();
glUseProgram(shader.pid);
// grab uniforms to modify
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
tinygltf::Model model;
if (!loadModel(model, filename.c_str())) return;
GLuint vao = bindModel(model);
// dbgModel(model); return;
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
// generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
glm::vec3 sun_color = glm::vec3(1.0);
while (!window.Close()) {
window.Resize();
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glm::vec3(0, 1, 0)); // rotate model on y axis
model_mat = trans * model_rot;
// build a model-view-projection
GLint w, h;
glfwGetWindowSize(window.window, &w, &h);
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
glUniform3fv(sun_position_u, 1, &sun_position[0]);
glUniform3fv(sun_color_u, 1, &sun_color[0]);
drawModel(vao, model);
glfwSwapBuffers(window.window);
glfwPollEvents();
}
}
static void error_callback(int error, const char *description) {
(void)error;
fprintf(stderr, "Error: %s\n", description);
}
int main(int argc, char **argv) {
std::string filename = "../../models/Cube/Cube.gltf";
if (argc > 1) {
filename = argv[1];
}
glfwSetErrorCallback(error_callback);
if (!glfwInit()) return -1;
// Force create OpenGL 3.3
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window);
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE;
#endif
glewInit();
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl;
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}

View File

@@ -28,7 +28,6 @@
#include "tiny_gltf.h"
#endif
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#define CheckGLErrors(desc) \
@@ -55,7 +54,9 @@ float eye[3], lookat[3], up[3];
GLFWwindow *window;
typedef struct { GLuint vb; } GLBufferState;
typedef struct {
GLuint vb;
} GLBufferState;
typedef struct {
std::vector<GLuint> diffuseTex; // for each primitive in mesh
@@ -254,6 +255,26 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) {
prevMouseY = mouse_y;
}
static size_t ComponentTypeByteSize(int type) {
switch (type) {
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
case TINYGLTF_COMPONENT_TYPE_BYTE:
return sizeof(char);
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
case TINYGLTF_COMPONENT_TYPE_SHORT:
return sizeof(short);
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
case TINYGLTF_COMPONENT_TYPE_INT:
return sizeof(int);
case TINYGLTF_COMPONENT_TYPE_FLOAT:
return sizeof(float);
case TINYGLTF_COMPONENT_TYPE_DOUBLE:
return sizeof(double);
default:
return 0;
}
}
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
// Buffer
{
@@ -264,14 +285,117 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
continue; // Unsupported bufferView.
}
int sparse_accessor = -1;
for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
const auto &accessor = model.accessors[a_i];
if (accessor.bufferView == i) {
std::cout << i << " is used by accessor " << a_i << std::endl;
if (accessor.sparse.isSparse) {
std::cout
<< "WARN: this bufferView has at least one sparse accessor to "
"it. We are going to load the data as patched by this "
"sparse accessor, not the original data"
<< std::endl;
sparse_accessor = a_i;
break;
}
}
}
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
GLBufferState state;
glGenBuffers(1, &state.vb);
glBindBuffer(bufferView.target, state.vb);
std::cout << "buffer.size= " << buffer.data.size()
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
if (sparse_accessor < 0)
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset,
GL_STATIC_DRAW);
else {
const auto accessor = model.accessors[sparse_accessor];
// copy the buffer to a temporary one for sparse patching
unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
bufferView.byteLength);
const size_t size_of_object_in_buffer =
ComponentTypeByteSize(accessor.componentType);
const size_t size_of_sparse_indices =
ComponentTypeByteSize(accessor.sparse.indices.componentType);
const auto &indices_buffer_view =
model.bufferViews[accessor.sparse.indices.bufferView];
const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
const auto &values_buffer_view =
model.bufferViews[accessor.sparse.values.bufferView];
const auto &values_buffer = model.buffers[values_buffer_view.buffer];
for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
++sparse_index) {
int index = 0;
// std::cout << "accessor.sparse.indices.componentType = " <<
// accessor.sparse.indices.componentType << std::endl;
switch (accessor.sparse.indices.componentType) {
case TINYGLTF_COMPONENT_TYPE_BYTE:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
index = (int)*(
unsigned char *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
case TINYGLTF_COMPONENT_TYPE_SHORT:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
index = (int)*(
unsigned short *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
case TINYGLTF_COMPONENT_TYPE_INT:
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
index = (int)*(
unsigned int *)(indices_buffer.data.data() +
indices_buffer_view.byteOffset +
accessor.sparse.indices.byteOffset +
(sparse_index * size_of_sparse_indices));
break;
}
std::cout << "updating sparse data at index : " << index
<< std::endl;
// index is now the target of the sparse index to patch in
const unsigned char *read_from =
values_buffer.data.data() +
(values_buffer_view.byteOffset +
accessor.sparse.values.byteOffset) +
(sparse_index * (size_of_object_in_buffer * accessor.type));
/*
std::cout << ((float*)read_from)[0] << "\n";
std::cout << ((float*)read_from)[1] << "\n";
std::cout << ((float*)read_from)[2] << "\n";
*/
unsigned char *write_to =
tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
}
// debug:
/*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
{
float* b = (float*)tmp_buffer;
std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
}*/
glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
GL_STATIC_DRAW);
delete[] tmp_buffer;
}
glBindBuffer(bufferView.target, 0);
gBufferState[i] = state;
@@ -279,55 +403,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
}
#if 0 // TODO(syoyo): Implement
// Texture
{
for (size_t i = 0; i < model.meshes.size(); i++) {
const tinygltf::Mesh &mesh = model.meshes[i];
// Texture
{
for (size_t i = 0; i < model.meshes.size(); i++) {
const tinygltf::Mesh &mesh = model.meshes[i];
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex[primId] = 0;
gMeshState[mesh.name].diffuseTex[primId] = 0;
if (primitive.material < 0) {
continue;
}
tinygltf::Material &mat = model.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (model.textures.find(diffuseTexName) != model.textures.end()) {
tinygltf::Texture &tex = model.textures[diffuseTexName];
if (scene.images.find(tex.source) != model.images.end()) {
tinygltf::Image &image = model.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (primitive.material < 0) {
continue;
}
tinygltf::Material &mat = model.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (model.textures.find(diffuseTexName) != model.textures.end()) {
tinygltf::Texture &tex = model.textures[diffuseTexName];
if (scene.images.find(tex.source) != model.images.end()) {
tinygltf::Image &image = model.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
#endif
glUseProgram(progId);
@@ -348,164 +472,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
#if 0 // TODO(syoyo): Implement
// Setup curves geometry extension
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
// Find curves primitive.
{
std::map<std::string, tinygltf::Mesh>::const_iterator it(
scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
scene.meshes.end());
// Find curves primitive.
{
std::map<std::string, tinygltf::Mesh>::const_iterator it(
scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
scene.meshes.end());
for (; it != itEnd; it++) {
const tinygltf::Mesh &mesh = it->second;
for (; it != itEnd; it++) {
const tinygltf::Mesh &mesh = it->second;
// Currently we only support one primitive per mesh.
if (mesh.primitives.size() > 1) {
continue;
}
// Currently we only support one primitive per mesh.
if (mesh.primitives.size() > 1) {
continue;
}
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
const tinygltf::Primitive &primitive = mesh.primitives[primId];
gMeshState[mesh.name].diffuseTex[primId] = 0;
gMeshState[mesh.name].diffuseTex[primId] = 0;
if (primitive.material.empty()) {
continue;
}
if (primitive.material.empty()) {
continue;
}
bool has_curves = false;
if (primitive.extras.IsObject()) {
if (primitive.extras.Has("ext_mode")) {
const tinygltf::Value::Object &o =
primitive.extras.Get<tinygltf::Value::Object>();
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
bool has_curves = false;
if (primitive.extras.IsObject()) {
if (primitive.extras.Has("ext_mode")) {
const tinygltf::Value::Object &o =
primitive.extras.Get<tinygltf::Value::Object>();
const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
if (ext_mode.IsString()) {
const std::string &str = ext_mode.Get<std::string>();
if (str.compare("curves") == 0) {
has_curves = true;
}
}
}
}
if (ext_mode.IsString()) {
const std::string &str = ext_mode.Get<std::string>();
if (str.compare("curves") == 0) {
has_curves = true;
}
}
}
}
if (!has_curves) {
continue;
}
if (!has_curves) {
continue;
}
// Construct curves buffer
const tinygltf::Accessor &vtx_accessor =
scene.accessors[primitive.attributes.find("POSITION")->second];
const tinygltf::Accessor &nverts_accessor =
scene.accessors[primitive.attributes.find("NVERTS")->second];
const tinygltf::BufferView &vtx_bufferView =
scene.bufferViews[vtx_accessor.bufferView];
const tinygltf::BufferView &nverts_bufferView =
scene.bufferViews[nverts_accessor.bufferView];
const tinygltf::Buffer &vtx_buffer =
scene.buffers[vtx_bufferView.buffer];
const tinygltf::Buffer &nverts_buffer =
scene.buffers[nverts_bufferView.buffer];
// Construct curves buffer
const tinygltf::Accessor &vtx_accessor =
scene.accessors[primitive.attributes.find("POSITION")->second];
const tinygltf::Accessor &nverts_accessor =
scene.accessors[primitive.attributes.find("NVERTS")->second];
const tinygltf::BufferView &vtx_bufferView =
scene.bufferViews[vtx_accessor.bufferView];
const tinygltf::BufferView &nverts_bufferView =
scene.bufferViews[nverts_accessor.bufferView];
const tinygltf::Buffer &vtx_buffer =
scene.buffers[vtx_bufferView.buffer];
const tinygltf::Buffer &nverts_buffer =
scene.buffers[nverts_bufferView.buffer];
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
// std::endl;
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
// std::endl;
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
// std::endl;
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
// std::endl;
// std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
// std::endl;
// std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
// std::endl;
// std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
// std::endl;
// std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
// std::endl;
const int *nverts =
reinterpret_cast<const int *>(nverts_buffer.data.data());
const float *vtx =
reinterpret_cast<const float *>(vtx_buffer.data.data());
const int *nverts =
reinterpret_cast<const int *>(nverts_buffer.data.data());
const float *vtx =
reinterpret_cast<const float *>(vtx_buffer.data.data());
// Convert to GL_LINES data.
std::vector<float> line_pts;
size_t vtx_offset = 0;
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
for (int n = 0; n < nverts[k] - 1; n++) {
// Convert to GL_LINES data.
std::vector<float> line_pts;
size_t vtx_offset = 0;
for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
for (int n = 0; n < nverts[k] - 1; n++) {
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
// << vtx[3 * (vtx_offset + n) + 1] << ", "
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
// std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
// << vtx[3 * (vtx_offset + n) + 1] << ", "
// << vtx[3 * (vtx_offset + n) + 2] << std::endl;
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
}
// std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
// << vtx[3 * (vtx_offset + n+1) + 1] << ", "
// << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
}
vtx_offset += nverts[k];
}
vtx_offset += nverts[k];
}
GLCurvesState state;
glGenBuffers(1, &state.vb);
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
line_pts.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLCurvesState state;
glGenBuffers(1, &state.vb);
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
line_pts.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
state.count = line_pts.size() / 3;
gCurvesMesh[mesh.name] = state;
state.count = line_pts.size() / 3;
gCurvesMesh[mesh.name] = state;
// Material
tinygltf::Material &mat = scene.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
tinygltf::Texture &tex = scene.textures[diffuseTexName];
if (scene.images.find(tex.source) != scene.images.end()) {
tinygltf::Image &image = scene.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Material
tinygltf::Material &mat = scene.materials[primitive.material];
// printf("material.name = %s\n", mat.name.c_str());
if (mat.values.find("diffuse") != mat.values.end()) {
std::string diffuseTexName = mat.values["diffuse"].string_value;
if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
tinygltf::Texture &tex = scene.textures[diffuseTexName];
if (scene.images.find(tex.source) != scene.images.end()) {
tinygltf::Image &image = scene.images[tex.source];
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(tex.target, texId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
// Ignore Texture.fomat.
GLenum format = GL_RGBA;
if (image.component == 3) {
format = GL_RGB;
}
glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
image.height, 0, format, tex.type,
&image.image.at(0));
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
CheckErrors("texImage2D");
glBindTexture(tex.target, 0);
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
printf("TexId = %d\n", texId);
gMeshState[mesh.name].diffuseTex[primId] = texId;
}
}
}
}
}
}
glUseProgram(progId);
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
glUseProgram(progId);
GLint vtloc = glGetAttribLocation(progId, "in_vertex");
GLint nrmloc = glGetAttribLocation(progId, "in_normal");
GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
gGLProgramState.attribs["POSITION"] = vtloc;
gGLProgramState.attribs["NORMAL"] = nrmloc;
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
gGLProgramState.attribs["POSITION"] = vtloc;
gGLProgramState.attribs["NORMAL"] = nrmloc;
gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
};
#endif
@@ -558,12 +682,13 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
(it->first.compare("TEXCOORD_0") == 0)) {
if (gGLProgramState.attribs[it->first] >= 0) {
// Compute byteStride from Accessor + BufferView combination.
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]);
int byteStride =
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
assert(byteStride != -1);
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride,
BUFFER_OFFSET(accessor.byteOffset));
accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, BUFFER_OFFSET(accessor.byteOffset));
CheckErrors("vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
CheckErrors("enable vertex attrib array");
@@ -617,32 +742,32 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) {
#if 0 // TODO(syoyo): Implement
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
(void)scene;
(void)scene;
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
return;
}
if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
return;
}
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
}
if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
}
GLCurvesState &state = gCurvesMesh[mesh.name];
GLCurvesState &state = gCurvesMesh[mesh.name];
if (gGLProgramState.attribs["POSITION"] >= 0) {
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
CheckErrors("curve: vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
CheckErrors("curve: enable vertex attrib array");
}
if (gGLProgramState.attribs["POSITION"] >= 0) {
glBindBuffer(GL_ARRAY_BUFFER, state.vb);
glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
CheckErrors("curve: vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
CheckErrors("curve: enable vertex attrib array");
}
glDrawArrays(GL_LINES, 0, state.count);
glDrawArrays(GL_LINES, 0, state.count);
if (gGLProgramState.attribs["POSITION"] >= 0) {
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
}
if (gGLProgramState.attribs["POSITION"] >= 0) {
glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
}
}
#endif
@@ -693,16 +818,16 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
static void DrawModel(tinygltf::Model &model) {
#if 0
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
for (; it != itEnd; it++) {
DrawMesh(scene, it->second);
DrawCurves(scene, it->second);
}
for (; it != itEnd; it++) {
DrawMesh(scene, it->second);
DrawCurves(scene, it->second);
}
#else
//If the glTF asset has at least one scene, and doesn't define a default one
//just show the first one we can find
// If the glTF asset has at least one scene, and doesn't define a default one
// just show the first one we can find
assert(model.scenes.size() > 0);
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
const tinygltf::Scene &scene = model.scenes[scene_to_display];
@@ -752,7 +877,8 @@ int main(int argc, char **argv) {
#ifdef _WIN32
#ifdef _DEBUG
std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf");
std::string input_filename(argv[1] ? argv[1]
: "../../../models/Cube/Cube.gltf");
#endif
#else
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
@@ -763,7 +889,8 @@ int main(int argc, char **argv) {
bool ret = false;
if (ext.compare("glb") == 0) {
// assume binary glTF.
ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
ret =
loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
} else {
// assume ascii glTF.
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
@@ -825,15 +952,14 @@ int main(int argc, char **argv) {
#ifdef _WIN32
#ifdef _DEBUG
const char *shader_frag_filename = "../shader.frag";
const char *shader_vert_filename = "../shader.vert";
const char *shader_frag_filename = "../shader.frag";
const char *shader_vert_filename = "../shader.vert";
#endif
#else
const char *shader_frag_filename = "shader.frag";
const char *shader_vert_filename = "shader.vert";
#endif
if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) {
return -1;
}

View File

@@ -175,7 +175,10 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
std::stringstream ss;
ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
}
ss << " ]";
@@ -190,7 +193,10 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
std::stringstream ss;
ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
}
ss << " ]";
@@ -228,7 +234,8 @@ static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) {
#endif
static std::string PrintValue(const std::string &name,
const tinygltf::Value &value, const int indent, const bool tag = true) {
const tinygltf::Value &value, const int indent,
const bool tag = true) {
std::stringstream ss;
if (value.IsObject()) {
@@ -242,36 +249,36 @@ static std::string PrintValue(const std::string &name,
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<std::string>();
} else {
ss << " " << value.Get<std::string>() << " ";
ss << Indent(indent) << value.Get<std::string>() << " ";
}
} else if (value.IsBool()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<bool>();
} else {
ss << " " << value.Get<bool>() << " ";
ss << Indent(indent) << value.Get<bool>() << " ";
}
} else if (value.IsNumber()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<double>();
} else {
ss << " " << value.Get<double>() << " ";
ss << Indent(indent) << value.Get<double>() << " ";
}
} else if (value.IsInt()) {
if (tag) {
ss << Indent(indent) << name << " : " << value.Get<int>();
} else {
ss << " " << value.Get<int>() << " ";
ss << Indent(indent) << value.Get<int>() << " ";
}
} else if (value.IsArray()) {
ss << Indent(indent) << name << " [ ";
// TODO(syoyo): Better pretty printing of array item
ss << Indent(indent) << name << " [ \n";
for (size_t i = 0; i < value.Size(); i++) {
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
if (i != (value.ArrayLen()-1)) {
ss << ", ";
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
if (i != (value.ArrayLen() - 1)) {
ss << ", \n";
}
}
ss << Indent(indent) << "] ";
ss << "\n" << Indent(indent) << "] ";
}
// @todo { binary }
@@ -315,6 +322,15 @@ static void DumpStringIntMap(const std::map<std::string, int> &m, int indent) {
}
}
static void DumpExtensions(const tinygltf::ExtensionMap &extension,
const int indent) {
// TODO(syoyo): pritty print Value
for (auto &e : extension) {
std::cout << Indent(indent) << e.first << std::endl;
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
}
}
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
std::cout << Indent(indent) << "material : " << primitive.material
<< std::endl;
@@ -326,17 +342,80 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
<< std::endl;
DumpStringIntMap(primitive.attributes, indent + 1);
DumpExtensions(primitive.extensions, indent);
std::cout << Indent(indent) << "extras :" << std::endl
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
if (!primitive.extensions_json_string.empty()) {
std::cout << Indent(indent + 1) << "extensions(JSON string) = "
<< primitive.extensions_json_string << "\n";
}
if (!primitive.extras_json_string.empty()) {
std::cout << Indent(indent + 1)
<< "extras(JSON string) = " << primitive.extras_json_string
<< "\n";
}
}
static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
{
// TODO(syoyo): pritty print Value
for (auto &e : extension) {
std::cout << Indent(indent) << e.first << std::endl;
std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
}
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
if (!texinfo.extensions_json_string.empty()) {
std::cout << Indent(indent)
<< "extensions(JSON string) = " << texinfo.extensions_json_string
<< "\n";
}
if (!texinfo.extras_json_string.empty()) {
std::cout << Indent(indent)
<< "extras(JSON string) = " << texinfo.extras_json_string << "\n";
}
}
static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpOcclusionTextureInfo(
const tinygltf::OcclusionTextureInfo &texinfo, const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr,
const int indent) {
std::cout << Indent(indent)
<< "baseColorFactor : " << PrintFloatArray(pbr.baseColorFactor)
<< "\n";
std::cout << Indent(indent) << "baseColorTexture :\n";
DumpTextureInfo(pbr.baseColorTexture, indent + 1);
std::cout << Indent(indent) << "metallicFactor : " << pbr.metallicFactor
<< "\n";
std::cout << Indent(indent) << "roughnessFactor : " << pbr.roughnessFactor
<< "\n";
std::cout << Indent(indent) << "metallicRoughnessTexture :\n";
DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1);
DumpExtensions(pbr.extensions, indent + 1);
std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n";
}
static void Dump(const tinygltf::Model &model) {
@@ -409,6 +488,30 @@ static void Dump(const tinygltf::Model &model) {
}
std::cout << "]" << std::endl;
}
if (accessor.sparse.isSparse) {
std::cout << Indent(2) << "sparse:" << std::endl;
std::cout << Indent(3) << "count : " << accessor.sparse.count
<< std::endl;
std::cout << Indent(3) << "indices: " << std::endl;
std::cout << Indent(4)
<< "bufferView : " << accessor.sparse.indices.bufferView
<< std::endl;
std::cout << Indent(4)
<< "byteOffset : " << accessor.sparse.indices.byteOffset
<< std::endl;
std::cout << Indent(4) << "componentType: "
<< PrintComponentType(accessor.sparse.indices.componentType)
<< "(" << accessor.sparse.indices.componentType << ")"
<< std::endl;
std::cout << Indent(3) << "values : " << std::endl;
std::cout << Indent(4)
<< "bufferView : " << accessor.sparse.values.bufferView
<< std::endl;
std::cout << Indent(4)
<< "byteOffset : " << accessor.sparse.values.byteOffset
<< std::endl;
}
}
}
@@ -467,6 +570,21 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2)
<< "target : " << PrintTarget(bufferView.target)
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(bufferView.extensions, 1);
std::cout << PrintValue("extras", bufferView.extras, 2) << std::endl;
if (!bufferView.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< bufferView.extensions_json_string << "\n";
}
if (!bufferView.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << bufferView.extras_json_string
<< "\n";
}
}
}
@@ -477,6 +595,21 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(1) << "name : " << buffer.name << std::endl;
std::cout << Indent(2) << "byteLength : " << buffer.data.size()
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(buffer.extensions, 1);
std::cout << PrintValue("extras", buffer.extras, 2) << std::endl;
if (!buffer.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< buffer.extensions_json_string << "\n";
}
if (!buffer.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << buffer.extras_json_string
<< "\n";
}
}
}
@@ -485,16 +618,55 @@ static void Dump(const tinygltf::Model &model) {
<< std::endl;
for (size_t i = 0; i < model.materials.size(); i++) {
const tinygltf::Material &material = model.materials[i];
std::cout << Indent(1) << "name : " << material.name << std::endl;
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
std::cout << Indent(1) << "name : " << material.name
<< std::endl;
std::cout << Indent(1) << "alphaMode : " << material.alphaMode
<< std::endl;
std::cout << Indent(1)
<< "alphaCutoff : " << material.alphaCutoff
<< std::endl;
std::cout << Indent(1) << "doubleSided : "
<< (material.doubleSided ? "true" : "false") << std::endl;
std::cout << Indent(1) << "emissiveFactor : "
<< PrintFloatArray(material.emissiveFactor) << std::endl;
std::cout << Indent(1) << "pbrMetallicRoughness :\n";
DumpPbrMetallicRoughness(material.pbrMetallicRoughness, 2);
std::cout << Indent(1) << "normalTexture :\n";
DumpNormalTextureInfo(material.normalTexture, 2);
std::cout << Indent(1) << "occlusionTexture :\n";
DumpOcclusionTextureInfo(material.occlusionTexture, 2);
std::cout << Indent(1) << "emissiveTexture :\n";
DumpTextureInfo(material.emissiveTexture, 2);
std::cout << Indent(1) << "---- legacy material parameter ----\n";
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl;
tinygltf::ParameterMap::const_iterator p(material.values.begin());
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
for (; p != pEnd; p++) {
std::cout << Indent(2) << p->first << ": "
<< PrintParameterValue(p->second) << std::endl;
}
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(material.extensions, 1);
std::cout << PrintValue("extras", material.extras, 2) << std::endl;
if (!material.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< material.extensions_json_string << "\n";
}
if (!material.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << material.extras_json_string
<< "\n";
}
}
}
@@ -518,6 +690,18 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2) << "height : " << image.height << std::endl;
std::cout << Indent(2) << "component : " << image.component << std::endl;
DumpExtensions(image.extensions, 1);
std::cout << PrintValue("extras", image.extras, 2) << std::endl;
if (!image.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< image.extensions_json_string << "\n";
}
if (!image.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << image.extras_json_string
<< "\n";
}
}
}
@@ -530,6 +714,18 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(1) << "source : " << texture.source
<< std::endl;
DumpExtensions(texture.extensions, 1);
std::cout << PrintValue("extras", texture.extras, 2) << std::endl;
if (!texture.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< texture.extensions_json_string << "\n";
}
if (!texture.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << texture.extras_json_string
<< "\n";
}
}
}
@@ -551,6 +747,20 @@ static void Dump(const tinygltf::Model &model) {
std::cout << Indent(2)
<< "wrapT : " << PrintWrapMode(sampler.wrapT)
<< std::endl;
DumpExtensions(sampler.extensions, 1);
std::cout << PrintValue("extras", sampler.extras, 2) << std::endl;
if (!sampler.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< sampler.extensions_json_string << "\n";
}
if (!sampler.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << sampler.extras_json_string
<< "\n";
}
}
}
@@ -583,12 +793,61 @@ static void Dump(const tinygltf::Model &model) {
<< "znear : " << camera.orthographic.znear
<< std::endl;
}
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(camera.extensions, 1);
std::cout << PrintValue("extras", camera.extras, 2) << std::endl;
if (!camera.extensions_json_string.empty()) {
std::cout << Indent(2) << "extensions(JSON string) = "
<< camera.extensions_json_string << "\n";
}
if (!camera.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << camera.extras_json_string
<< "\n";
}
}
}
{
std::cout << "skins(items=" << model.skins.size() << ")" << std::endl;
for (size_t i = 0; i < model.skins.size(); i++) {
const tinygltf::Skin &skin = model.skins[i];
std::cout << Indent(1) << "name : " << skin.name << std::endl;
std::cout << Indent(2)
<< "inverseBindMatrices : " << skin.inverseBindMatrices
<< std::endl;
std::cout << Indent(2) << "skeleton : " << skin.skeleton
<< std::endl;
std::cout << Indent(2)
<< "joints : " << PrintIntArray(skin.joints)
<< std::endl;
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(skin.extensions, 1);
std::cout << PrintValue("extras", skin.extras, 2) << std::endl;
if (!skin.extensions_json_string.empty()) {
std::cout << Indent(2)
<< "extensions(JSON string) = " << skin.extensions_json_string
<< "\n";
}
if (!skin.extras_json_string.empty()) {
std::cout << Indent(2)
<< "extras(JSON string) = " << skin.extras_json_string
<< "\n";
}
}
}
// toplevel extensions
{
std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
std::cout << "extensions(items=" << model.extensions.size() << ")"
<< std::endl;
DumpExtensions(model.extensions, 1);
}
}
@@ -599,29 +858,39 @@ int main(int argc, char **argv) {
exit(1);
}
// Store original JSON string for `extras` and `extensions`
bool store_original_json_for_extras_and_extensions = false;
if (argc > 2) {
store_original_json_for_extras_and_extensions = true;
}
tinygltf::Model model;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
std::string warn;
std::string warn;
std::string input_filename(argv[1]);
std::string ext = GetFilePathExtension(input_filename);
gltf_ctx.SetStoreOriginalJSONForExtrasAndExtensions(
store_original_json_for_extras_and_extensions);
bool ret = false;
if (ext.compare("glb") == 0) {
std::cout << "Reading binary glTF" << std::endl;
// assume binary glTF.
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn,
input_filename.c_str());
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
ret =
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
}
if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str());
}
if (!err.empty()) {
printf("Err: %s\n", err.c_str());
}

View File

@@ -0,0 +1,67 @@
{
"scenes": [
{
"nodes": [0]
}
],
"nodes": [
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 1
},
"indices": 0
}
]
}
],
"buffers": [
{
"uri": "simpleTriangle.bin",
"byteLength": 44
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 1e300,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 8,
"byteLength": 36,
"target": 34962
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 3,
"type": "VEC3",
"max": [1, 1, 0],
"min": [0, 0, 0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -0,0 +1,53 @@
{
"scenes": [],
"nodes": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 0
}
]
}
],
"buffers": [
{
"uri": "simpleTriangle.bin",
"byteLength": 44
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
},
{
"buffer": 1,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"images": [
{
"bufferView": 1,
"mimeType": "image/png"
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -0,0 +1,36 @@
{
"scenes": [],
"nodes": [],
"buffers": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 0
}
]
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"accessors": [
{
"bufferView": 1,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

View File

@@ -0,0 +1,36 @@
{
"scenes": [],
"nodes": [],
"buffers": [],
"meshes": [
{
"primitives": [
{
"attributes": {},
"indices": 1
}
]
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 6,
"target": 34963
}
],
"accessors": [
{
"bufferView": 1,
"componentType": 5123,
"count": 3,
"type": "SCALAR",
"max": [2],
"min": [0]
}
],
"asset": {
"version": "2.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 B

View File

@@ -0,0 +1,224 @@
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
35
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1.000001
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
-0,
-0,
1
],
"min": [
0,
-0,
-1,
-1
],
"type": "VEC4"
},
{
"bufferView": 4,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1
],
"min": [
-1,
-1
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"byteOffset": 0,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"0comment": "Use Cube_MetallicRoughness.png to reduce scene filesize",
"uri": "Cube_MetallicRoughness.png"
},
{
"uri": "Cube_MetallicRoughness.png"
}
],
"materials": [
{
"emissiveTexture": {
"index": 0,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"scale": [
1,
-1
]
}
}
}
},
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"rotation": 1.57079632679,
"scale": [
0.5,
0.5
]
}
}
}
}
}
],
"meshes": [
{
"name": "Cube",
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"samplers": [
{}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -0,0 +1,6 @@
Added KHR_texture_transform property to Cube scene.
License: Donated by Norbert Nopper for glTF testing.
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube

View File

@@ -14,6 +14,7 @@ import subprocess
sample_model_dir = "/home/syoyo/work/glTF-Sample-Models"
base_model_dir = os.path.join(sample_model_dir, "2.0")
# Include `glTF-Draco` when you build `loader_example` with draco support.
kinds = [ "glTF", "glTF-Binary", "glTF-Embedded", "glTF-MaterialsCommon"]
# ---------------------------------

View File

@@ -13,6 +13,14 @@
#include <sstream>
#include <fstream>
static JsonDocument JsonConstruct(const char* str)
{
JsonDocument doc;
JsonParse(doc, str, strlen(str));
return doc;
}
TEST_CASE("parse-error", "[parse]") {
tinygltf::Model model;
@@ -20,7 +28,7 @@ TEST_CASE("parse-error", "[parse]") {
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", strlen("bora"), /* basedir*/ "");
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", static_cast<int>(strlen("bora")), /* basedir*/ "");
REQUIRE(false == ret);
@@ -37,7 +45,7 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
}
@@ -82,7 +90,246 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
REQUIRE(m.materials[0].extensions.size() == 1);
REQUIRE(m.materials[0].extensions.count("VENDOR_material_some_ext") == 1);
}
}
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-primitive-indices.gltf");
REQUIRE_THAT(err,
Catch::Contains("primitive indices accessor out of bounds"));
REQUIRE_FALSE(ret);
}
TEST_CASE("invalid-buffer-view-index", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-buffer-view-index.gltf");
REQUIRE_THAT(err, Catch::Contains("accessor[0] invalid bufferView"));
REQUIRE_FALSE(ret);
}
TEST_CASE("invalid-buffer-index", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/invalid-buffer-index.gltf");
REQUIRE_THAT(
err, Catch::Contains("image[0] buffer \"1\" not found in the scene."));
REQUIRE_FALSE(ret);
}
TEST_CASE("glb-invalid-length", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// This glb has a much longer length than the provided data and should fail
// initial range checks.
const unsigned char glb_invalid_length[] = "glTF"
"\x20\x00\x00\x00" "\x6c\x66\x00\x00" //
// | version | length |
"\x02\x00\x00\x00" "\x4a\x53\x4f\x4e{}"; //
// | model length | model format |
bool ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, glb_invalid_length,
sizeof(glb_invalid_length));
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
REQUIRE_FALSE(ret);
}
TEST_CASE("integer-out-of-bounds", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/BoundsChecking/integer-out-of-bounds.gltf");
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
REQUIRE_FALSE(ret);
}
TEST_CASE("parse-integer", "[bounds-checking]") {
SECTION("parses valid numbers") {
std::string err;
int result = 123;
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"zero\" : 0}"), "zero",
true));
REQUIRE(err == "");
REQUIRE(result == 0);
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": -1234}"), "int",
true));
REQUIRE(err == "");
REQUIRE(result == -1234);
}
SECTION("detects missing properties") {
std::string err;
int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", true));
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
REQUIRE(result == -1);
}
SECTION("handled missing but not required properties") {
std::string err;
int result = -1;
CHECK_FALSE(
tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", false));
REQUIRE(err == "");
REQUIRE(result == -1);
}
SECTION("invalid integers") {
std::string err;
int result = -1;
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
// Excessively large values and NaN aren't allowed either.
err.clear();
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
err.clear();
{
JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan));
CHECK_FALSE(tinygltf::ParseIntegerProperty(
&result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
}
}
}
TEST_CASE("parse-unsigned", "[bounds-checking]") {
SECTION("parses valid unsigned integers") {
// Use string-based parsing here, using the initializer list syntax doesn't
// parse 0 as unsigned.
auto zero_obj = JsonConstruct("{\"zero\": 0}");
std::string err;
size_t result = 123;
CHECK(
tinygltf::ParseUnsignedProperty(&result, &err, zero_obj, "zero", true));
REQUIRE(err == "");
REQUIRE(result == 0);
}
SECTION("invalid integers") {
std::string err;
size_t result = -1;
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": -1234}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
// Excessively large values and NaN aren't allowed either.
err.clear();
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
err.clear();
{
JsonDocument o;
double nan = std::numeric_limits<double>::quiet_NaN();
tinygltf::JsonAddMember(o, "int", json(nan));
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
&result, &err, o,
"int", true));
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
}
}
}
TEST_CASE("parse-integer-array", "[bounds-checking]") {
SECTION("parses valid integers") {
std::string err;
std::vector<int> result;
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
JsonConstruct("{\"x\": [-1, 2, 3]}"), "x", true));
REQUIRE(err == "");
REQUIRE(result.size() == 3);
REQUIRE(result[0] == -1);
REQUIRE(result[1] == 2);
REQUIRE(result[2] == 3);
}
SECTION("invalid integers") {
std::string err;
std::vector<int> result;
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
&result, &err, JsonConstruct("{\"x\": [-1, 1e300, 3]}"), "x", true));
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
}
}
TEST_CASE("pbr-khr-texture-transform", "[material]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/Cube-texture-ext/Cube-textransform.gltf");
REQUIRE(ret == true);
REQUIRE(model.materials.size() == 2);
REQUIRE(model.materials[0].emissiveTexture.extensions.count("KHR_texture_transform") == 1);
REQUIRE(model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].IsObject());
tinygltf::Value::Object &texform = model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].Get<tinygltf::Value::Object>();
REQUIRE(texform.count("scale"));
REQUIRE(texform["scale"].IsArray());
// Note: It looks json.hpp parse integer JSON number as integer, not floating point.
// IsNumber return true either value is int or floating point.
REQUIRE(texform["scale"].Get(0).IsNumber());
REQUIRE(texform["scale"].Get(1).IsNumber());
double scale[2];
scale[0] = texform["scale"].Get(0).GetNumberAsDouble();
scale[1] = texform["scale"].Get(1).GetNumberAsDouble();
REQUIRE(scale[0] == Approx(1.0));
REQUIRE(scale[1] == Approx(-1.0));
}

File diff suppressed because it is too large Load Diff