mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 18:58:53 +00:00
Compare commits
158 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb0a8794c3 | ||
|
|
60e22f3281 | ||
|
|
4cfd2849fb | ||
|
|
a5416707c9 | ||
|
|
8ec9af7f2e | ||
|
|
40982716f9 | ||
|
|
4bdc96fb9b | ||
|
|
96ecea080a | ||
|
|
22bfc843ee | ||
|
|
eaa25a307a | ||
|
|
ab600b8e72 | ||
|
|
eb9d29c06e | ||
|
|
57356933c5 | ||
|
|
c3d6716c56 | ||
|
|
ac5e09f8c3 | ||
|
|
e2c3fe1c0b | ||
|
|
973d9b3394 | ||
|
|
28ad4ab7b8 | ||
|
|
0227ae5d9b | ||
|
|
a0a62bde1c | ||
|
|
23d1ff2880 | ||
|
|
bcf2ce586e | ||
|
|
aa3c5a1cad | ||
|
|
db2fbeec9d | ||
|
|
c4166e4c60 | ||
|
|
1cf179d377 | ||
|
|
ddc14f8ba6 | ||
|
|
72f4a55edd | ||
|
|
379bb612f1 | ||
|
|
1da4e5d633 | ||
|
|
4e47bc7799 | ||
|
|
9cc3e91968 | ||
|
|
d09788d10f | ||
|
|
a11f6e1939 | ||
|
|
8ced108571 | ||
|
|
3eb65e269a | ||
|
|
1322c7bf09 | ||
|
|
49651fe3d9 | ||
|
|
db93a87c4a | ||
|
|
7b0d81bf12 | ||
|
|
2e8a115d7e | ||
|
|
ae9364902a | ||
|
|
06d2fbdae6 | ||
|
|
d5ff5cbfb1 | ||
|
|
1d20520680 | ||
|
|
4ab0386d09 | ||
|
|
a471770f38 | ||
|
|
125d8e50a9 | ||
|
|
45cac78709 | ||
|
|
a9d86c1af4 | ||
|
|
2f26eddac4 | ||
|
|
a0939550ca | ||
|
|
58ab95be2f | ||
|
|
bf0e4f8e45 | ||
|
|
30f333c607 | ||
|
|
419162716e | ||
|
|
9533c352a1 | ||
|
|
9ff3d93084 | ||
|
|
aea514a975 | ||
|
|
05a4456948 | ||
|
|
6e08b17ce3 | ||
|
|
fb256609f2 | ||
|
|
5cecef2b92 | ||
|
|
1100f0f1eb | ||
|
|
2b66c81f67 | ||
|
|
f29375f59b | ||
|
|
79e3df26a8 | ||
|
|
e3cf5edb94 | ||
|
|
b74fadef8e | ||
|
|
a11709a9ff | ||
|
|
cf668683f9 | ||
|
|
817bbcfb58 | ||
|
|
23467959ca | ||
|
|
6f08785e9f | ||
|
|
ff2b1f92dd | ||
|
|
e886247329 | ||
|
|
83bb1a48d7 | ||
|
|
c3353e1acd | ||
|
|
81b672bcc2 | ||
|
|
cece6ee6d2 | ||
|
|
31f875ddbc | ||
|
|
8dccf9bf4e | ||
|
|
508dcfa2e6 | ||
|
|
7e009041e3 | ||
|
|
14977937c2 | ||
|
|
8bb18fbd9c | ||
|
|
9eeaf20133 | ||
|
|
a34aa8ea77 | ||
|
|
59b2966f81 | ||
|
|
7481011fd9 | ||
|
|
0d2b6efa6f | ||
|
|
ce7fa7419b | ||
|
|
906f98fa74 | ||
|
|
d2a2703ec5 | ||
|
|
95f05757d6 | ||
|
|
ab63db6318 | ||
|
|
6ff95392b0 | ||
|
|
c29bd3d9ce | ||
|
|
63419a11e1 | ||
|
|
06c30c4d04 | ||
|
|
67e6160a9a | ||
|
|
a3b8b355ae | ||
|
|
5145394239 | ||
|
|
67aa2ca75e | ||
|
|
ce25385eab | ||
|
|
6143c6662b | ||
|
|
81d75df48a | ||
|
|
83ccb9f28d | ||
|
|
9b6f52e98a | ||
|
|
5cecc41db9 | ||
|
|
208c3058bf | ||
|
|
cba5d6caae | ||
|
|
d1e1472992 | ||
|
|
ff51570c26 | ||
|
|
a472a3fa0f | ||
|
|
1f160d5b8f | ||
|
|
5150a46072 | ||
|
|
cea69e37a5 | ||
|
|
8b56c016ab | ||
|
|
c7e205be87 | ||
|
|
6dba6c6aac | ||
|
|
6df800d2b6 | ||
|
|
2f044e77f1 | ||
|
|
af5a5ef026 | ||
|
|
6591ba4461 | ||
|
|
74c3c10121 | ||
|
|
ad63bf748b | ||
|
|
5d43cf8e64 | ||
|
|
4e2988eebd | ||
|
|
ee179b2cb6 | ||
|
|
4ebd6368fb | ||
|
|
67d3d2504d | ||
|
|
d9a468bbb4 | ||
|
|
c7bae71f7f | ||
|
|
f93642c196 | ||
|
|
f68d5e1f2a | ||
|
|
1c84fc22a5 | ||
|
|
150f243b1b | ||
|
|
0ee273fdfa | ||
|
|
046400b17f | ||
|
|
89fd93f815 | ||
|
|
e940337796 | ||
|
|
1b5f476d95 | ||
|
|
52936a00e0 | ||
|
|
f3ef880029 | ||
|
|
1af7c1d784 | ||
|
|
c0b79afecc | ||
|
|
c49461b7c2 | ||
|
|
051f4be2f1 | ||
|
|
4557b6aa22 | ||
|
|
b2d7d88dbc | ||
|
|
b7ca7c9381 | ||
|
|
0ffedcbe79 | ||
|
|
80faac5238 | ||
|
|
2a9d9deb67 | ||
|
|
8a98d98cd9 | ||
|
|
689edcbef6 | ||
|
|
820ede87db |
12
.travis.yml
12
.travis.yml
@@ -31,6 +31,17 @@ matrix:
|
|||||||
- addons: *1
|
- addons: *1
|
||||||
compiler: clang
|
compiler: clang
|
||||||
env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
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:
|
before_install:
|
||||||
- ./.travis-before-install.sh
|
- ./.travis-before-install.sh
|
||||||
@@ -43,6 +54,7 @@ script:
|
|||||||
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
|
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
|
||||||
- ./loader_example ./models/Cube/Cube.gltf
|
- ./loader_example ./models/Cube/Cube.gltf
|
||||||
- cd tests
|
- cd tests
|
||||||
|
- clang++ -v
|
||||||
- make
|
- make
|
||||||
- ./tester
|
- ./tester
|
||||||
- ./tester_noexcept
|
- ./tester_noexcept
|
||||||
|
|||||||
@@ -4,14 +4,21 @@ PROJECT (tinygltf)
|
|||||||
|
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
ADD_EXECUTABLE ( loader_example
|
option(TINYGLTF_BUILD_EXAMPLES "Build examples" ON)
|
||||||
loader_example.cc
|
|
||||||
)
|
|
||||||
|
|
||||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
if (TINYGLTF_BUILD_EXAMPLES)
|
||||||
ADD_SUBDIRECTORY ( examples/glview )
|
ADD_EXECUTABLE ( loader_example
|
||||||
ADD_SUBDIRECTORY ( examples/validator )
|
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
|
INSTALL ( FILES
|
||||||
json.hpp
|
json.hpp
|
||||||
stb_image.h
|
stb_image.h
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -7,6 +7,8 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
- 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.2.0 release(Support loading 16bit PNG. Sparse accessor support)
|
||||||
- v2.1.0 release(Draco support)
|
- v2.1.0 release(Draco support)
|
||||||
- v2.0.0 release(22 Aug, 2018)!
|
- v2.0.0 release(22 Aug, 2018)!
|
||||||
@@ -32,8 +34,11 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
* Moderate parsing time and memory consumption.
|
* Moderate parsing time and memory consumption.
|
||||||
* glTF specification v2.0.0
|
* glTF specification v2.0.0
|
||||||
* [x] ASCII glTF
|
* [x] ASCII glTF
|
||||||
|
* [x] Load
|
||||||
|
* [x] Save
|
||||||
* [x] Binary glTF(GLB)
|
* [x] Binary glTF(GLB)
|
||||||
* [x] PBR material description
|
* [x] Load
|
||||||
|
* [x] Save(.bin embedded .glb)
|
||||||
* Buffers
|
* Buffers
|
||||||
* [x] Parse BASE64 encoded embedded buffer data(DataURI).
|
* [x] Parse BASE64 encoded embedded buffer data(DataURI).
|
||||||
* [x] Load `.bin` file.
|
* [x] Load `.bin` file.
|
||||||
@@ -53,6 +58,13 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
* [x] Image save
|
* [x] Image save
|
||||||
* Extensions
|
* Extensions
|
||||||
* [x] Draco mesh decoding
|
* [x] Draco mesh decoding
|
||||||
|
* [ ] Draco mesh encoding
|
||||||
|
|
||||||
|
## 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
|
## Examples
|
||||||
|
|
||||||
@@ -67,6 +79,10 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF
|
* 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.
|
* [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
|
* [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)
|
* Your projects here! (Please send PR)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
@@ -76,7 +92,7 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
* [x] Load Draco compressed mesh
|
* [x] Load Draco compressed mesh
|
||||||
* [ ] Save Draco compressed mesh
|
* [ ] Save Draco compressed mesh
|
||||||
* [ ] Open3DGC?
|
* [ ] Open3DGC?
|
||||||
* [ ] Support `extensions` and `extras` property
|
* [x] Support `extensions` and `extras` property
|
||||||
* [ ] HDR image?
|
* [ ] HDR image?
|
||||||
* [ ] OpenEXR extension through TinyEXR.
|
* [ ] OpenEXR extension through TinyEXR.
|
||||||
* [ ] 16bit PNG support in Serialization
|
* [ ] 16bit PNG support in Serialization
|
||||||
@@ -143,17 +159,22 @@ if (!ret) {
|
|||||||
* `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_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 `: 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_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
|
### Saving gltTF 2.0 model
|
||||||
* [ ] Buffers.
|
|
||||||
|
* Buffers.
|
||||||
* [x] To file
|
* [x] To file
|
||||||
* [x] Embedded
|
* [x] Embedded
|
||||||
* [ ] Draco compressed?
|
* [ ] Draco compressed?
|
||||||
* [x] Images
|
* [x] Images
|
||||||
* [x] To file
|
* [x] To file
|
||||||
* [x] Embedded
|
* [x] Embedded
|
||||||
* [ ] Binary(.glb)
|
* Binary(.glb)
|
||||||
|
* [x] .bin embedded single .glb
|
||||||
|
* [ ] External .bin
|
||||||
|
|
||||||
## Running tests.
|
## Running tests.
|
||||||
|
|
||||||
@@ -181,8 +202,17 @@ $ ./tester
|
|||||||
$ ./tester_noexcept
|
$ ./tester_noexcept
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Fuzzing tests
|
||||||
|
|
||||||
|
See `tests/fuzzer` for details.
|
||||||
|
|
||||||
|
After running fuzzer on Ryzen9 3950X a week, at least `LoadASCIIFromString` looks safe except for out-of-memory error in Fuzzer.
|
||||||
|
We may be better to introduce bounded memory size checking when parsing glTF data.
|
||||||
|
|
||||||
## Third party licenses
|
## Third party licenses
|
||||||
|
|
||||||
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
|
* 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.
|
* stb_image : Public domain.
|
||||||
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
|
* 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/
|
||||||
|
* dlib(uridecode, uriencode) : Copyright (C) 2003 Davis E. King Boost Software License 1.0. http://dlib.net/dlib/server/server_http.cpp.html
|
||||||
|
|||||||
@@ -1,365 +1,364 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
#include "shaders.h"
|
#include "shaders.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
|
||||||
#define TINYGLTF_IMPLEMENTATION
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
#define TINYGLTF_NOEXCEPTION
|
#define TINYGLTF_NOEXCEPTION
|
||||||
#define JSON_NOEXCEPTION
|
#define JSON_NOEXCEPTION
|
||||||
#include "../../tiny_gltf.h"
|
#include "../../tiny_gltf.h"
|
||||||
|
|
||||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||||
|
|
||||||
bool loadModel(tinygltf::Model &model, const char *filename) {
|
bool loadModel(tinygltf::Model &model, const char *filename) {
|
||||||
tinygltf::TinyGLTF loader;
|
tinygltf::TinyGLTF loader;
|
||||||
std::string err;
|
std::string err;
|
||||||
std::string warn;
|
std::string warn;
|
||||||
|
|
||||||
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
|
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
|
||||||
if (!warn.empty()) {
|
if (!warn.empty()) {
|
||||||
std::cout << "WARN: " << warn << std::endl;
|
std::cout << "WARN: " << warn << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cout << "ERR: " << err << std::endl;
|
std::cout << "ERR: " << err << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
std::cout << "Failed to load glTF: " << filename << std::endl;
|
std::cout << "Failed to load glTF: " << filename << std::endl;
|
||||||
else
|
else
|
||||||
std::cout << "Loaded glTF: " << filename << std::endl;
|
std::cout << "Loaded glTF: " << filename << std::endl;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
||||||
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||||
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
|
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
|
||||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||||
if (bufferView.target == 0) { // TODO impl drawarrays
|
if (bufferView.target == 0) { // TODO impl drawarrays
|
||||||
std::cout << "WARN: bufferView.target is zero" << std::endl;
|
std::cout << "WARN: bufferView.target is zero" << std::endl;
|
||||||
continue; // Unsupported bufferView.
|
continue; // Unsupported bufferView.
|
||||||
/*
|
/*
|
||||||
From spec2.0 readme:
|
From spec2.0 readme:
|
||||||
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
|
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
|
||||||
... drawArrays function should be used with a count equal to
|
... drawArrays function should be used with a count equal to
|
||||||
the count property of any of the accessors referenced by the
|
the count property of any of the accessors referenced by the
|
||||||
attributes property (they are all equal for a given
|
attributes property (they are all equal for a given
|
||||||
primitive).
|
primitive).
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
|
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
|
||||||
std::cout << "bufferview.target " << bufferView.target << std::endl;
|
std::cout << "bufferview.target " << bufferView.target << std::endl;
|
||||||
|
|
||||||
GLuint vbo;
|
GLuint vbo;
|
||||||
glGenBuffers(1, &vbo);
|
glGenBuffers(1, &vbo);
|
||||||
vbos[i] = vbo;
|
vbos[i] = vbo;
|
||||||
glBindBuffer(bufferView.target, vbo);
|
glBindBuffer(bufferView.target, vbo);
|
||||||
|
|
||||||
std::cout << "buffer.data.size = " << buffer.data.size()
|
std::cout << "buffer.data.size = " << buffer.data.size()
|
||||||
<< ", bufferview.byteOffset = " << bufferView.byteOffset
|
<< ", bufferview.byteOffset = " << bufferView.byteOffset
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
glBufferData(bufferView.target, bufferView.byteLength,
|
glBufferData(bufferView.target, bufferView.byteLength,
|
||||||
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
||||||
tinygltf::Primitive primitive = mesh.primitives[i];
|
tinygltf::Primitive primitive = mesh.primitives[i];
|
||||||
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
||||||
|
|
||||||
for (auto &attrib : primitive.attributes) {
|
for (auto &attrib : primitive.attributes) {
|
||||||
tinygltf::Accessor accessor = model.accessors[attrib.second];
|
tinygltf::Accessor accessor = model.accessors[attrib.second];
|
||||||
int byteStride =
|
int byteStride =
|
||||||
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
accessor.ByteStride(model.bufferViews[accessor.bufferView]);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
|
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
|
||||||
|
|
||||||
int size = 1;
|
int size = 1;
|
||||||
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
|
if (accessor.type != TINYGLTF_TYPE_SCALAR) {
|
||||||
size = accessor.type;
|
size = accessor.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vaa = -1;
|
int vaa = -1;
|
||||||
if (attrib.first.compare("POSITION") == 0) vaa = 0;
|
if (attrib.first.compare("POSITION") == 0) vaa = 0;
|
||||||
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
|
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
|
||||||
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
|
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
|
||||||
if (vaa > -1) {
|
if (vaa > -1) {
|
||||||
glEnableVertexAttribArray(vaa);
|
glEnableVertexAttribArray(vaa);
|
||||||
glVertexAttribPointer(vaa, size, accessor.componentType,
|
glVertexAttribPointer(vaa, size, accessor.componentType,
|
||||||
accessor.normalized ? GL_TRUE : GL_FALSE,
|
accessor.normalized ? GL_TRUE : GL_FALSE,
|
||||||
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
byteStride, BUFFER_OFFSET(accessor.byteOffset));
|
||||||
} else
|
} else
|
||||||
std::cout << "vaa missing: " << attrib.first << std::endl;
|
std::cout << "vaa missing: " << attrib.first << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint texid;
|
GLuint texid;
|
||||||
glGenTextures(1, &texid);
|
glGenTextures(1, &texid);
|
||||||
|
|
||||||
tinygltf::Texture &tex = model.textures[0];
|
tinygltf::Texture &tex = model.textures[0];
|
||||||
tinygltf::Image &image = model.images[tex.source];
|
tinygltf::Image &image = model.images[tex.source];
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texid);
|
glBindTexture(GL_TEXTURE_2D, texid);
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_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_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
|
||||||
GLenum format = GL_RGBA;
|
GLenum format = GL_RGBA;
|
||||||
|
|
||||||
if (image.component == 1) {
|
if (image.component == 1) {
|
||||||
format = GL_RED;
|
format = GL_RED;
|
||||||
} else if (image.component == 2) {
|
} else if (image.component == 2) {
|
||||||
format = GL_RG;
|
format = GL_RG;
|
||||||
} else if (image.component == 3) {
|
} else if (image.component == 3) {
|
||||||
format = GL_RGB;
|
format = GL_RGB;
|
||||||
} else {
|
} else {
|
||||||
// ???
|
// ???
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum type = GL_UNSIGNED_BYTE;
|
GLenum type = GL_UNSIGNED_BYTE;
|
||||||
if (image.bits == 8) {
|
if (image.bits == 8) {
|
||||||
// ok
|
// ok
|
||||||
} else if (image.bits == 16) {
|
} else if (image.bits == 16) {
|
||||||
type = GL_UNSIGNED_SHORT;
|
type = GL_UNSIGNED_SHORT;
|
||||||
} else {
|
} else {
|
||||||
// ???
|
// ???
|
||||||
}
|
}
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||||
format, type, &image.image.at(0));
|
format, type, &image.image.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return vbos;
|
return vbos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind models
|
// bind models
|
||||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
||||||
tinygltf::Node &node) {
|
tinygltf::Node &node) {
|
||||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GLuint bindModel(tinygltf::Model &model) {
|
GLuint bindModel(tinygltf::Model &model) {
|
||||||
std::map<int, GLuint> vbos;
|
std::map<int, GLuint> vbos;
|
||||||
GLuint vao;
|
GLuint vao;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
// cleanup vbos
|
// cleanup vbos
|
||||||
for (size_t i = 0; i < vbos.size(); ++i) {
|
for (size_t i = 0; i < vbos.size(); ++i) {
|
||||||
glDeleteBuffers(1, &vbos[i]);
|
glDeleteBuffers(1, &vbos[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return vao;
|
return vao;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||||
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
||||||
tinygltf::Primitive primitive = mesh.primitives[i];
|
tinygltf::Primitive primitive = mesh.primitives[i];
|
||||||
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
||||||
|
|
||||||
glDrawElements(primitive.mode, indexAccessor.count,
|
glDrawElements(primitive.mode, indexAccessor.count,
|
||||||
indexAccessor.componentType,
|
indexAccessor.componentType,
|
||||||
BUFFER_OFFSET(indexAccessor.byteOffset));
|
BUFFER_OFFSET(indexAccessor.byteOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursively draw node and children nodes of model
|
// recursively draw node and children nodes of model
|
||||||
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
||||||
drawMesh(model, model.meshes[node.mesh]);
|
drawMesh(model, model.meshes[node.mesh]);
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
drawModelNodes(model, model.nodes[node.children[i]]);
|
drawModelNodes(model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void drawModel(GLuint vao, tinygltf::Model &model) {
|
void drawModel(GLuint vao, tinygltf::Model &model) {
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||||
drawModelNodes(model, model.nodes[scene.nodes[i]]);
|
drawModelNodes(model, model.nodes[scene.nodes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbgModel(tinygltf::Model &model) {
|
void dbgModel(tinygltf::Model &model) {
|
||||||
for (auto &mesh : model.meshes) {
|
for (auto &mesh : model.meshes) {
|
||||||
std::cout << "mesh : " << mesh.name << std::endl;
|
std::cout << "mesh : " << mesh.name << std::endl;
|
||||||
for (auto &primitive : mesh.primitives) {
|
for (auto &primitive : mesh.primitives) {
|
||||||
const tinygltf::Accessor &indexAccessor =
|
const tinygltf::Accessor &indexAccessor =
|
||||||
model.accessors[primitive.indices];
|
model.accessors[primitive.indices];
|
||||||
|
|
||||||
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
|
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
|
||||||
<< indexAccessor.componentType << std::endl;
|
<< indexAccessor.componentType << std::endl;
|
||||||
|
|
||||||
tinygltf::Material &mat = model.materials[primitive.material];
|
tinygltf::Material &mat = model.materials[primitive.material];
|
||||||
for (auto &mats : mat.values) {
|
for (auto &mats : mat.values) {
|
||||||
std::cout << "mat : " << mats.first.c_str() << std::endl;
|
std::cout << "mat : " << mats.first.c_str() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &image : model.images) {
|
for (auto &image : model.images) {
|
||||||
std::cout << "image name : " << image.uri << std::endl;
|
std::cout << "image name : " << image.uri << std::endl;
|
||||||
std::cout << " size : " << image.image.size() << std::endl;
|
std::cout << " size : " << image.image.size() << std::endl;
|
||||||
std::cout << " w/h : " << image.width << "/" << image.height
|
std::cout << " w/h : " << image.width << "/" << image.height
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "indices : " << primitive.indices << std::endl;
|
std::cout << "indices : " << primitive.indices << std::endl;
|
||||||
std::cout << "mode : "
|
std::cout << "mode : "
|
||||||
<< "(" << primitive.mode << ")" << std::endl;
|
<< "(" << primitive.mode << ")" << std::endl;
|
||||||
|
|
||||||
for (auto &attrib : primitive.attributes) {
|
for (auto &attrib : primitive.attributes) {
|
||||||
std::cout << "attribute : " << attrib.first.c_str() << std::endl;
|
std::cout << "attribute : " << attrib.first.c_str() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
|
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
|
||||||
// Camera matrix
|
// Camera matrix
|
||||||
glm::mat4 view = glm::lookAt(
|
glm::mat4 view = glm::lookAt(
|
||||||
pos, // Camera in World Space
|
pos, // Camera in World Space
|
||||||
lookat, // and looks at the origin
|
lookat, // and looks at the origin
|
||||||
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
|
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
|
||||||
);
|
);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
|
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
|
||||||
int h) {
|
int h) {
|
||||||
glm::mat4 Projection =
|
glm::mat4 Projection =
|
||||||
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
|
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
|
||||||
|
|
||||||
// Or, for an ortho camera :
|
// Or, for an ortho camera :
|
||||||
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
|
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
|
||||||
// // In world coordinates
|
// // In world coordinates
|
||||||
|
|
||||||
glm::mat4 mvp = Projection * view_mat * model_mat;
|
glm::mat4 mvp = Projection * view_mat * model_mat;
|
||||||
|
|
||||||
return mvp;
|
return mvp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayLoop(Window &window, const std::string &filename) {
|
void displayLoop(Window &window, const std::string &filename) {
|
||||||
Shaders shader = Shaders();
|
Shaders shader = Shaders();
|
||||||
glUseProgram(shader.pid);
|
glUseProgram(shader.pid);
|
||||||
|
|
||||||
// grab uniforms to modify
|
// grab uniforms to modify
|
||||||
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
|
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
|
||||||
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
|
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
|
||||||
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
|
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
|
||||||
|
|
||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
if (!loadModel(model, filename.c_str())) return;
|
if (!loadModel(model, filename.c_str())) return;
|
||||||
|
|
||||||
GLuint vao = bindModel(model);
|
GLuint vao = bindModel(model);
|
||||||
// dbgModel(model); return;
|
// dbgModel(model); return;
|
||||||
|
|
||||||
// Model matrix : an identity matrix (model will be at the origin)
|
// Model matrix : an identity matrix (model will be at the origin)
|
||||||
glm::mat4 model_mat = glm::mat4(1.0f);
|
glm::mat4 model_mat = glm::mat4(1.0f);
|
||||||
glm::mat4 model_rot = glm::mat4(1.0f);
|
glm::mat4 model_rot = glm::mat4(1.0f);
|
||||||
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
|
glm::vec3 model_pos = glm::vec3(-3, 0, -3);
|
||||||
|
|
||||||
// generate a camera view, based on eye-position and lookAt world-position
|
// 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::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_position = glm::vec3(3.0, 10.0, -5.0);
|
||||||
glm::vec3 sun_color = glm::vec3(1.0);
|
glm::vec3 sun_color = glm::vec3(1.0);
|
||||||
|
|
||||||
while (!window.Close()) {
|
while (!window.Close()) {
|
||||||
window.Resize();
|
window.Resize();
|
||||||
|
|
||||||
glClearColor(0.2, 0.2, 0.2, 1.0);
|
glClearColor(0.2, 0.2, 0.2, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
glm::mat4 trans =
|
glm::mat4 trans =
|
||||||
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
|
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
|
||||||
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
|
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
|
||||||
glm::vec3(0, 1, 0)); // rotate model on y axis
|
glm::vec3(0, 1, 0)); // rotate model on y axis
|
||||||
model_mat = trans * model_rot;
|
model_mat = trans * model_rot;
|
||||||
|
|
||||||
// build a model-view-projection
|
// build a model-view-projection
|
||||||
GLint w, h;
|
GLint w, h;
|
||||||
glfwGetWindowSize(window.window, &w, &h);
|
glfwGetWindowSize(window.window, &w, &h);
|
||||||
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
|
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
|
||||||
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
|
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
|
||||||
|
|
||||||
glUniform3fv(sun_position_u, 1, &sun_position[0]);
|
glUniform3fv(sun_position_u, 1, &sun_position[0]);
|
||||||
glUniform3fv(sun_color_u, 1, &sun_color[0]);
|
glUniform3fv(sun_color_u, 1, &sun_color[0]);
|
||||||
|
|
||||||
drawModel(vao, model);
|
drawModel(vao, model);
|
||||||
glfwSwapBuffers(window.window);
|
glfwSwapBuffers(window.window);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error_callback(int error, const char *description) {
|
static void error_callback(int error, const char *description) {
|
||||||
(void)error;
|
(void)error;
|
||||||
fprintf(stderr, "Error: %s\n", description);
|
fprintf(stderr, "Error: %s\n", description);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
std::string filename = "../../models/Cube/Cube.gltf";
|
std::string filename = "../../models/Cube/Cube.gltf";
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
filename = argv[1];
|
filename = argv[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSetErrorCallback(error_callback);
|
glfwSetErrorCallback(error_callback);
|
||||||
|
|
||||||
if (!glfwInit()) return -1;
|
if (!glfwInit()) return -1;
|
||||||
|
|
||||||
// Force create OpenGL 3.3
|
// Force create OpenGL 3.3
|
||||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
Window window = Window(800, 600, "TinyGLTF basic example");
|
||||||
Window window = Window(800, 600, "TinyGLTF basic example");
|
glfwMakeContextCurrent(window.window);
|
||||||
glfwMakeContextCurrent(window.window);
|
|
||||||
|
#ifdef __APPLE__
|
||||||
#ifdef __APPLE__
|
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
|
||||||
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
|
glewExperimental = GL_TRUE;
|
||||||
glewExperimental = GL_TRUE;
|
#endif
|
||||||
#endif
|
|
||||||
|
glewInit();
|
||||||
glewInit();
|
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
|
||||||
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
|
<< std::endl;
|
||||||
<< std::endl;
|
|
||||||
|
if (!GLEW_VERSION_3_3) {
|
||||||
if (!GLEW_VERSION_3_3) {
|
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
|
||||||
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
|
return EXIT_FAILURE;
|
||||||
return EXIT_FAILURE;
|
}
|
||||||
}
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glDepthFunc(GL_LESS);
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glEnable(GL_BLEND);
|
||||||
glEnable(GL_BLEND);
|
|
||||||
|
displayLoop(window, filename);
|
||||||
displayLoop(window, filename);
|
|
||||||
|
glfwTerminate();
|
||||||
glfwTerminate();
|
return 0;
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
5
examples/mesh-modify/Makefile
Normal file
5
examples/mesh-modify/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#EXTRA_CXXFLAGS := -fsanitize=address -fno-omit-frame-pointer -Wall -Werror -Weverything -Wno-c++11-long-long -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded
|
||||||
|
EXTRA_CXXFLAGS :=
|
||||||
|
|
||||||
|
all:
|
||||||
|
clang++ -std=c++11 -g -O1 -I../../ -I../common $(EXTRA_CXXFLAGS) -o mesh-modify mesh-modify.cc mesh-util.cc tinygltf_impl.cc
|
||||||
13
examples/mesh-modify/README.md
Normal file
13
examples/mesh-modify/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Mesh modify experiment
|
||||||
|
|
||||||
|
Sometimes we want to tweak mesh attributes(e.g. vertex position, uv coord, etc).
|
||||||
|
glTF itself does not allow ASCII representation of such data.
|
||||||
|
|
||||||
|
This example show how to
|
||||||
|
|
||||||
|
- Export mesh data from .bin to .obj
|
||||||
|
- Import mesh data to .bin(update corresponding buffer data) from .obj
|
||||||
|
|
||||||
|
## Requirement
|
||||||
|
|
||||||
|
Assume Buffer is stored as external file(`.bin`)
|
||||||
760
examples/mesh-modify/mesh-modify.cc
Normal file
760
examples/mesh-modify/mesh-modify.cc
Normal file
@@ -0,0 +1,760 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#if !defined(__ANDROID__) && !defined(_WIN32)
|
||||||
|
#include <wordexp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Weverything"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../../json.hpp"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "../../tiny_gltf.h"
|
||||||
|
#else
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mesh-util.hh"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-function"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static std::string PrintMode(int mode) {
|
||||||
|
if (mode == TINYGLTF_MODE_POINTS) {
|
||||||
|
return "POINTS";
|
||||||
|
} else if (mode == TINYGLTF_MODE_LINE) {
|
||||||
|
return "LINE";
|
||||||
|
} else if (mode == TINYGLTF_MODE_LINE_LOOP) {
|
||||||
|
return "LINE_LOOP";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLES) {
|
||||||
|
return "TRIANGLES";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) {
|
||||||
|
return "TRIANGLE_FAN";
|
||||||
|
} else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) {
|
||||||
|
return "TRIANGLE_STRIP";
|
||||||
|
}
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintTarget(int target) {
|
||||||
|
if (target == 34962) {
|
||||||
|
return "GL_ARRAY_BUFFER";
|
||||||
|
} else if (target == 34963) {
|
||||||
|
return "GL_ELEMENT_ARRAY_BUFFER";
|
||||||
|
} else {
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintType(int ty) {
|
||||||
|
if (ty == TINYGLTF_TYPE_SCALAR) {
|
||||||
|
return "SCALAR";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VECTOR) {
|
||||||
|
return "VECTOR";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC2) {
|
||||||
|
return "VEC2";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC3) {
|
||||||
|
return "VEC3";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_VEC4) {
|
||||||
|
return "VEC4";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MATRIX) {
|
||||||
|
return "MATRIX";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT2) {
|
||||||
|
return "MAT2";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT3) {
|
||||||
|
return "MAT3";
|
||||||
|
} else if (ty == TINYGLTF_TYPE_MAT4) {
|
||||||
|
return "MAT4";
|
||||||
|
}
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string PrintComponentType(int ty) {
|
||||||
|
if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
return "BYTE";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
return "UNSIGNED_BYTE";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
return "SHORT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
return "UNSIGNED_SHORT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_INT) {
|
||||||
|
return "INT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
|
||||||
|
return "UNSIGNED_INT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||||
|
return "FLOAT";
|
||||||
|
} else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
||||||
|
return "DOUBLE";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "**UNKNOWN**";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||||
|
// TODO(syoyo): Support more data type
|
||||||
|
struct VertexAttrib {
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// Value are converted to float type.
|
||||||
|
std::vector<float> data;
|
||||||
|
|
||||||
|
// Corresponding info in binary data
|
||||||
|
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||||
|
int component_type; // storage type. e.g.
|
||||||
|
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||||
|
uint64_t buffer_offset{0};
|
||||||
|
size_t buffer_length{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshPrim {
|
||||||
|
std::string name;
|
||||||
|
int32_t id{-1};
|
||||||
|
|
||||||
|
int mode{TINYGLTF_MODE_TRIANGLES};
|
||||||
|
|
||||||
|
VertexAttrib position; // vec3
|
||||||
|
VertexAttrib normal; // vec3
|
||||||
|
VertexAttrib tangent; // vec4
|
||||||
|
VertexAttrib color; // vec3 or vec4
|
||||||
|
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||||
|
std::map<int, VertexAttrib> weights; // <slot, attrib>
|
||||||
|
std::map<int, VertexAttrib>
|
||||||
|
joints; // <slot, attrib> store data as float type
|
||||||
|
|
||||||
|
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||||
|
std::vector<uint32_t> indices; // vertex indices
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static std::string GetFilePathExtension(const std::string &FileName) {
|
||||||
|
if (FileName.find_last_of(".") != std::string::npos)
|
||||||
|
return FileName.substr(FileName.find_last_of(".") + 1);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> LoadBin(const std::string &filename) {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
std::ifstream is(filename, std::ios::binary | std::ios::in | std::ios::ate);
|
||||||
|
|
||||||
|
if (is.is_open()) {
|
||||||
|
size_t size = size_t(is.tellg());
|
||||||
|
is.seekg(0, std::ios::beg);
|
||||||
|
if (size < 4) {
|
||||||
|
std::cerr << "File size is zero or too short: " << size << "\n";
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.resize(size);
|
||||||
|
is.read(reinterpret_cast<char *>(data.data()), std::streamsize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(syoyo): Use C++17 like filesystem library
|
||||||
|
|
||||||
|
bool FileExists(const std::string &abs_filename) {
|
||||||
|
bool ret;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO(syoyo): Support utf8 filepath
|
||||||
|
FILE *fp = nullptr;
|
||||||
|
errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
|
||||||
|
if (err != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
FILE *fp = fopen(abs_filename.c_str(), "rb");
|
||||||
|
#endif
|
||||||
|
if (fp) {
|
||||||
|
ret = true;
|
||||||
|
fclose(fp);
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string JoinPath(const std::string &path0,
|
||||||
|
const std::string &path1) {
|
||||||
|
if (path0.empty()) {
|
||||||
|
return path1;
|
||||||
|
} else {
|
||||||
|
// check '/'
|
||||||
|
char lastChar = *path0.rbegin();
|
||||||
|
if (lastChar != '/') {
|
||||||
|
return path0 + std::string("/") + path1;
|
||||||
|
} else {
|
||||||
|
return path0 + path1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ExpandFilePath(const std::string &filepath) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
||||||
|
char *str = new char[len];
|
||||||
|
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
||||||
|
|
||||||
|
std::string s(str);
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
|
defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
||||||
|
// no expansion
|
||||||
|
std::string s = filepath;
|
||||||
|
#else
|
||||||
|
std::string s;
|
||||||
|
wordexp_t p;
|
||||||
|
|
||||||
|
if (filepath.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quote the string to keep any spaces in filepath intact.
|
||||||
|
std::string quoted_path = "\"" + filepath + "\"";
|
||||||
|
// char** w;
|
||||||
|
int ret = wordexp(quoted_path.c_str(), &p, 0);
|
||||||
|
if (ret) {
|
||||||
|
// err
|
||||||
|
s = filepath;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use first element only.
|
||||||
|
if (p.we_wordv) {
|
||||||
|
s = std::string(p.we_wordv[0]);
|
||||||
|
wordfree(&p);
|
||||||
|
} else {
|
||||||
|
s = filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return s;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string FindFile(const std::vector<std::string> &paths,
|
||||||
|
const std::string &filepath) {
|
||||||
|
for (size_t i = 0; i < paths.size(); i++) {
|
||||||
|
std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath));
|
||||||
|
if (FileExists(absPath)) {
|
||||||
|
return absPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static std::string GetBaseDir(const std::string &filepath) {
|
||||||
|
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||||
|
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int GetSlotId(const std::string &name) {
|
||||||
|
if (name.rfind("TEXCOORD_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "TEXCOORD_%d", &id);
|
||||||
|
return id;
|
||||||
|
} else if (name.rfind("WEIGHTS_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "WEIGHTS_%d", &id);
|
||||||
|
return id;
|
||||||
|
} else if (name.rfind("JOINTS_", 0) == 0) {
|
||||||
|
int id = 0;
|
||||||
|
sscanf(name.c_str(), "JOINTS_%d", &id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsAttributeSupported(const std::string &name) {
|
||||||
|
constexpr int max_slots = 8;
|
||||||
|
|
||||||
|
if (name.compare("POSITION") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.compare("NORMAL") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name.compare("TANGENT") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "TEXCOORD_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "WEIGHTS_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < max_slots; i++) {
|
||||||
|
std::string n = "JOINTS_" + std::to_string(i);
|
||||||
|
if (n.compare(name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float Unpack(const unsigned char *ptr, int type) {
|
||||||
|
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
unsigned char data = *ptr;
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
char data = static_cast<char>(*ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||||
|
return float(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||||
|
float data = *reinterpret_cast<const float *>(ptr);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t UnpackIndex(const unsigned char *ptr, int type) {
|
||||||
|
if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
|
||||||
|
unsigned char data = *ptr;
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_BYTE) {
|
||||||
|
char data = static_cast<char>(*ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
|
||||||
|
uint16_t data = *reinterpret_cast<const uint16_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
int16_t data = *reinterpret_cast<const int16_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_INT) {
|
||||||
|
// TODO(syoyo): Check overflow(2G+ index)
|
||||||
|
int32_t data = *reinterpret_cast<const int32_t *>(ptr);
|
||||||
|
return uint32_t(data);
|
||||||
|
} else if (type == TINYGLTF_COMPONENT_TYPE_SHORT) {
|
||||||
|
uint32_t data = *reinterpret_cast<const uint32_t *>(ptr);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: Unsupported type: " << PrintComponentType(type) << "\n";
|
||||||
|
return static_cast<uint32_t>(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DumpMesh(const tinygltf::Model &model, const tinygltf::Mesh &mesh,
|
||||||
|
example::MeshPrim *out) {
|
||||||
|
for (size_t i = 0; i < mesh.primitives.size(); i++) {
|
||||||
|
const tinygltf::Primitive &primitive = mesh.primitives[i];
|
||||||
|
|
||||||
|
if (primitive.indices < 0) {
|
||||||
|
std::cerr << "Primitive indices must be provided\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// indices.
|
||||||
|
{
|
||||||
|
const tinygltf::Accessor &indexAccessor =
|
||||||
|
model.accessors[size_t(primitive.indices)];
|
||||||
|
|
||||||
|
size_t num_elements = indexAccessor.count;
|
||||||
|
std::cout << "index.elements = " << num_elements << "\n";
|
||||||
|
|
||||||
|
size_t byte_stride = ComponentTypeByteSize(indexAccessor.componentType);
|
||||||
|
|
||||||
|
const tinygltf::BufferView &indexBufferView =
|
||||||
|
model.bufferViews[size_t(indexAccessor.bufferView)];
|
||||||
|
|
||||||
|
// should be 34963(ELEMENT_ARRAY_BUFFER)
|
||||||
|
std::cout << "index.target = " << PrintTarget(indexBufferView.target) << "\n";
|
||||||
|
if (indexBufferView.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) {
|
||||||
|
std::cerr << "indexBufferView.target must be ELEMENT_ARRAY_BUFFER\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Buffer &indexBuffer =
|
||||||
|
model.buffers[size_t(indexBufferView.buffer)];
|
||||||
|
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < num_elements; k++) {
|
||||||
|
|
||||||
|
// TODO(syoyo): out-of-bounds check.
|
||||||
|
const unsigned char *ptr = indexBuffer.data.data() +
|
||||||
|
indexBufferView.byteOffset + (k * byte_stride) +
|
||||||
|
indexAccessor.byteOffset;
|
||||||
|
|
||||||
|
uint32_t idx = UnpackIndex(ptr, indexAccessor.componentType);
|
||||||
|
|
||||||
|
std::cout << "vertex_index[" << k << "] = " << idx << "\n";
|
||||||
|
|
||||||
|
indices.push_back(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
out->indices = indices;
|
||||||
|
out->indices_type = indexAccessor.componentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
{
|
||||||
|
std::map<std::string, int>::const_iterator it(
|
||||||
|
primitive.attributes.begin());
|
||||||
|
std::map<std::string, int>::const_iterator itEnd(
|
||||||
|
primitive.attributes.end());
|
||||||
|
|
||||||
|
for (; it != itEnd; it++) {
|
||||||
|
// it->first would be "POSITION", "NORMAL", "TEXCOORD_0", ...
|
||||||
|
if (!IsAttributeSupported(it->first)) {
|
||||||
|
std::cout << "Unsupported attribute: " << it->first << "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size_t(it->second) >= model.accessors.size()) {
|
||||||
|
std::cerr << "Invalid accessor id: " << it->second << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Accessor &accessor =
|
||||||
|
model.accessors[size_t(it->second)];
|
||||||
|
|
||||||
|
size_t elem_size = 1;
|
||||||
|
if (accessor.type == TINYGLTF_TYPE_SCALAR) {
|
||||||
|
elem_size = 1;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC2) {
|
||||||
|
elem_size = 2;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC3) {
|
||||||
|
elem_size = 3;
|
||||||
|
} else if (accessor.type == TINYGLTF_TYPE_VEC4) {
|
||||||
|
elem_size = 4;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Invalid or unsupported accessor type: "
|
||||||
|
<< PrintType(accessor.type) << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << PrintComponentType(accessor.componentType) << "\n";
|
||||||
|
|
||||||
|
size_t byte_stride = ComponentTypeByteSize(accessor.componentType);
|
||||||
|
|
||||||
|
std::cout << "attribute: " << it->first << "\n";
|
||||||
|
// if (gGLProgramState.attribs[it->first] >= 0) {
|
||||||
|
// Compute byteStride from Accessor + BufferView combination.
|
||||||
|
int byteStride =
|
||||||
|
accessor.ByteStride(model.bufferViews[size_t(accessor.bufferView)]);
|
||||||
|
assert(byteStride != -1);
|
||||||
|
|
||||||
|
std::cout << "byteOffset: " << accessor.byteOffset << "\n";
|
||||||
|
|
||||||
|
const tinygltf::BufferView &bufferView =
|
||||||
|
model.bufferViews[size_t(accessor.bufferView)];
|
||||||
|
const tinygltf::Buffer &buffer =
|
||||||
|
model.buffers[size_t(bufferView.buffer)];
|
||||||
|
|
||||||
|
size_t num_elems = accessor.count * elem_size;
|
||||||
|
|
||||||
|
example::VertexAttrib attrib;
|
||||||
|
for (size_t k = 0; k < num_elems; k++) {
|
||||||
|
// TODO(syoyo): out-of-bounds check.
|
||||||
|
const unsigned char *ptr = buffer.data.data() +
|
||||||
|
bufferView.byteOffset + (k * byte_stride) +
|
||||||
|
accessor.byteOffset;
|
||||||
|
float value = Unpack(ptr, accessor.componentType);
|
||||||
|
std::cout << "[" << k << "] value = " << value << "\n";
|
||||||
|
attrib.data.push_back(value);
|
||||||
|
}
|
||||||
|
attrib.component_type = accessor.componentType;
|
||||||
|
attrib.data_type = accessor.type;
|
||||||
|
attrib.name = it->first;
|
||||||
|
|
||||||
|
if (attrib.name.compare("POSITION") == 0) {
|
||||||
|
out->position = attrib;
|
||||||
|
} else if (attrib.name.compare("NORMAL") == 0) {
|
||||||
|
out->normal = attrib;
|
||||||
|
} else if (attrib.name.compare("TANGENT") == 0) {
|
||||||
|
out->tangent = attrib;
|
||||||
|
} else if (attrib.name.rfind("TEXCOORD_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "texcoord[" << id << "]\n";
|
||||||
|
out->texcoords[id] = attrib;
|
||||||
|
} else if (attrib.name.rfind("JOINTS_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "joints[" << id << "]\n";
|
||||||
|
out->joints[id] = attrib;
|
||||||
|
} else if (attrib.name.rfind("WEIGHTS_", 0) == 0) {
|
||||||
|
int id = GetSlotId(attrib.name);
|
||||||
|
std::cout << "weights[" << id << "]\n";
|
||||||
|
out->weights[id] = attrib;
|
||||||
|
} else {
|
||||||
|
std::cerr << "???: attrib.name = " << attrib.name << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Accessor &indexAccessor =
|
||||||
|
model.accessors[size_t(primitive.indices)];
|
||||||
|
(void)indexAccessor;
|
||||||
|
PrintMode(primitive.mode);
|
||||||
|
if (primitive.mode != TINYGLTF_MODE_TRIANGLES) {
|
||||||
|
std::cerr << "Supported Primitive mode is TRIANGLES only at the moment\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->mode = primitive.mode;
|
||||||
|
out->name = mesh.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model,
|
||||||
|
std::vector<example::MeshPrim> *outs) {
|
||||||
|
// Get .bin data
|
||||||
|
{
|
||||||
|
if (model.buffers.size() != 1) {
|
||||||
|
std::cerr << "Single element of `buffers` is supported at the moment.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinygltf::Buffer &buffer = model.buffers[0];
|
||||||
|
if (buffer.uri.empty()) {
|
||||||
|
std::cerr << "buffer.uri must be a filepath.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.data.size() < 4) {
|
||||||
|
std::cerr << "Invalid buffer.byteLength.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> search_paths;
|
||||||
|
search_paths.push_back(asset_path);
|
||||||
|
|
||||||
|
std::string abs_filepath = FindFile(search_paths, buffer.uri);
|
||||||
|
std::vector<uint8_t> bin = LoadBin(buffer.uri);
|
||||||
|
if (bin.size() != buffer.data.size()) {
|
||||||
|
std::cerr << "Byte size mismatch. Failed to load file: " << buffer.uri
|
||||||
|
<< "\n";
|
||||||
|
std::cerr << " .bin size = " << bin.size() << ", size in 'buffer.uri' = " << buffer.data.size() << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &mesh : model.meshes) {
|
||||||
|
std::cout << "mesh.name: " << mesh.name << "\n";
|
||||||
|
|
||||||
|
example::MeshPrim output;
|
||||||
|
bool ret = DumpMesh(model, mesh, &output);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outs->push_back(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
std::cout << "mesh-dump input.gltf" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF loader;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string input_filename(argv[1] ? argv[1]
|
||||||
|
: "../../../models/Cube/Cube.gltf");
|
||||||
|
#else
|
||||||
|
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string ext = GetFilePathExtension(input_filename);
|
||||||
|
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
if (ext.compare("glb") == 0) {
|
||||||
|
// assume binary glTF.
|
||||||
|
ret = loader.LoadBinaryFromFile(&model, &err, &warn,
|
||||||
|
input_filename.c_str());
|
||||||
|
} else {
|
||||||
|
// assume ascii glTF.
|
||||||
|
ret =
|
||||||
|
loader.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());
|
||||||
|
}
|
||||||
|
if (!ret) {
|
||||||
|
printf("Failed to load .glTF : %s\n", argv[1]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json j;
|
||||||
|
{
|
||||||
|
std::ifstream i(input_filename);
|
||||||
|
i >> j;
|
||||||
|
}
|
||||||
|
std::cout << "j = " << j << "\n";
|
||||||
|
|
||||||
|
json j_patch = R"([
|
||||||
|
{ "op": "add", "path": "/buffers/-", "value": {
|
||||||
|
"name": "plane/data",
|
||||||
|
"byteLength": 480,
|
||||||
|
"uri": "plane1.bin"
|
||||||
|
} }
|
||||||
|
])"_json;
|
||||||
|
|
||||||
|
// a JSON value
|
||||||
|
json j_original = R"({
|
||||||
|
"baz": ["one", "two", "three"],
|
||||||
|
"foo": "bar"
|
||||||
|
})"_json;
|
||||||
|
|
||||||
|
//json j_patch = R"([
|
||||||
|
// { "op": "remove", "path": "/buffers" }
|
||||||
|
//])"_json;
|
||||||
|
|
||||||
|
std::cout << "patch = " << j_patch.dump(2) << "\n";
|
||||||
|
|
||||||
|
json j_ret = j.patch(j_patch);
|
||||||
|
std::cout << "patched = " << j_ret.dump(2) << "\n";
|
||||||
|
|
||||||
|
std::string basedir = GetBaseDir(input_filename);
|
||||||
|
std::vector<example::MeshPrim> meshes;
|
||||||
|
bool ret = ExtractMesh(basedir, model, &meshes);
|
||||||
|
|
||||||
|
size_t n = 0;
|
||||||
|
for (const auto &mesh : meshes) {
|
||||||
|
// Assume no duplicated name in .glTF data
|
||||||
|
std::string filename;
|
||||||
|
if (mesh.name.empty()) {
|
||||||
|
filename = "untitled-" + std::to_string(n) + ".obj";
|
||||||
|
} else {
|
||||||
|
filename = mesh.name + ".obj";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flip_y = true; // flip texcoord Y?
|
||||||
|
bool ok = example::SaveAsObjMesh(filename, mesh,);
|
||||||
|
if (!ok) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
#else
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string input_filename(argv[1]);
|
||||||
|
|
||||||
|
// Require facevarying layout?
|
||||||
|
// false = try to keep GL-like mesh data as much as possible.
|
||||||
|
// true = reorder vertex data and re-assign vertex indices.
|
||||||
|
bool facevarying = false;
|
||||||
|
|
||||||
|
example::MeshPrim mesh;
|
||||||
|
bool ok = example::LoadObjMesh(input_filename, facevarying, &mesh);
|
||||||
|
if (!ok) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintMeshPrim(mesh);
|
||||||
|
|
||||||
|
std::string output_filename("output.gltf");
|
||||||
|
|
||||||
|
ok = example::SaveAsGLTFMesh(output_filename, mesh);
|
||||||
|
if (!ok) {
|
||||||
|
std::cerr << "Failed to save mesh as glTF\n";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
std::cout << "Write glTF: " << output_filename << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
1369
examples/mesh-modify/mesh-util.cc
Normal file
1369
examples/mesh-modify/mesh-util.cc
Normal file
File diff suppressed because it is too large
Load Diff
76
examples/mesh-modify/mesh-util.hh
Normal file
76
examples/mesh-modify/mesh-util.hh
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
// TODO(syoyo): Support sparse accessor(sparse vertex attribute).
|
||||||
|
// TODO(syoyo): Support more data type
|
||||||
|
struct VertexAttrib {
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// Value are converted to float type.
|
||||||
|
std::vector<float> data;
|
||||||
|
|
||||||
|
// Corresponding info in binary data
|
||||||
|
int data_type; // e.g. TINYGLTF_TYPE_VEC2
|
||||||
|
int component_type; // storage type. e.g.
|
||||||
|
// TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT
|
||||||
|
uint64_t buffer_offset{0};
|
||||||
|
size_t buffer_length{0};
|
||||||
|
|
||||||
|
// Optional.
|
||||||
|
std::vector<double> minValues;
|
||||||
|
std::vector<double> maxValues;
|
||||||
|
|
||||||
|
size_t numElements() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshPrim {
|
||||||
|
std::string name;
|
||||||
|
int32_t id{-1};
|
||||||
|
|
||||||
|
int mode; // e.g. TRIANGLES
|
||||||
|
|
||||||
|
VertexAttrib position; // vec3
|
||||||
|
VertexAttrib normal; // vec3
|
||||||
|
VertexAttrib tangent; // vec4
|
||||||
|
VertexAttrib color; // vec3 or vec4
|
||||||
|
std::map<int, VertexAttrib> texcoords; // <slot, attrib> vec2
|
||||||
|
std::map<int, VertexAttrib> weights; // <slot, attrib> vec4
|
||||||
|
std::map<int, VertexAttrib>
|
||||||
|
joints; // <slot, attrib> store data as float type
|
||||||
|
|
||||||
|
|
||||||
|
// min/max of index value. -1 = undef
|
||||||
|
int indices_min{-1};
|
||||||
|
int indices_max{-1};
|
||||||
|
int indices_type{-1}; // storage type(componentType) of `indices`.
|
||||||
|
std::vector<uint32_t> indices; // vertex indices
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Save MeshPrim as wavefront .obj
|
||||||
|
///
|
||||||
|
bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Save MeshPrim as glTF mesh
|
||||||
|
///
|
||||||
|
bool SaveAsGLTFMesh(const std::string &filename, const MeshPrim &mesh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Loads .obj and convert to MeshPrim
|
||||||
|
///
|
||||||
|
/// @param[in] facevarying Construct mesh with facevarying vertex layout(default false)
|
||||||
|
///
|
||||||
|
bool LoadObjMesh(const std::string &filename, bool facevarying, MeshPrim *mesh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Print MeshPrim datra
|
||||||
|
///
|
||||||
|
void PrintMeshPrim(const MeshPrim &mesh);
|
||||||
|
|
||||||
|
} // namespace example
|
||||||
7
examples/mesh-modify/meson.build
Normal file
7
examples/mesh-modify/meson.build
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
project('mesh-modify', 'cpp', default_options : ['cpp_std=c++11'])
|
||||||
|
|
||||||
|
thread_dep = dependency('threads')
|
||||||
|
|
||||||
|
incdir = include_directories(['../../', '../common'])
|
||||||
|
|
||||||
|
executable('mesh-modify', ['mesh-modify.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep)
|
||||||
@@ -150,6 +150,7 @@ bool LoadObj(const std::string &filename, float scale,
|
|||||||
tinyobj::attrib_t attrib;
|
tinyobj::attrib_t attrib;
|
||||||
std::vector<tinyobj::shape_t> shapes;
|
std::vector<tinyobj::shape_t> shapes;
|
||||||
std::vector<tinyobj::material_t> materials;
|
std::vector<tinyobj::material_t> materials;
|
||||||
|
std::string warn;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
std::string basedir = GetBaseDir(filename) + "/";
|
std::string basedir = GetBaseDir(filename) + "/";
|
||||||
@@ -158,12 +159,16 @@ bool LoadObj(const std::string &filename, float scale,
|
|||||||
// auto t_start = std::chrono::system_clock::now();
|
// auto t_start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
bool ret =
|
bool ret =
|
||||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename.c_str(),
|
||||||
basepath, /* triangulate */ true);
|
basepath, /* triangulate */ true);
|
||||||
|
|
||||||
// auto t_end = std::chrono::system_clock::now();
|
// auto t_end = std::chrono::system_clock::now();
|
||||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||||
|
|
||||||
|
if (!warn.empty()) {
|
||||||
|
std::cout << warn << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (!err.empty()) {
|
if (!err.empty()) {
|
||||||
std::cerr << err << std::endl;
|
std::cerr << err << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,10 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "[ ";
|
ss << "[ ";
|
||||||
for (size_t i = 0; i < arr.size(); i++) {
|
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 << " ]";
|
ss << " ]";
|
||||||
|
|
||||||
@@ -190,7 +193,10 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "[ ";
|
ss << "[ ";
|
||||||
for (size_t i = 0; i < arr.size(); i++) {
|
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 << " ]";
|
ss << " ]";
|
||||||
|
|
||||||
@@ -243,35 +249,36 @@ static std::string PrintValue(const std::string &name,
|
|||||||
if (tag) {
|
if (tag) {
|
||||||
ss << Indent(indent) << name << " : " << value.Get<std::string>();
|
ss << Indent(indent) << name << " : " << value.Get<std::string>();
|
||||||
} else {
|
} else {
|
||||||
ss << " " << value.Get<std::string>() << " ";
|
ss << Indent(indent) << value.Get<std::string>() << " ";
|
||||||
}
|
}
|
||||||
} else if (value.IsBool()) {
|
} else if (value.IsBool()) {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
ss << Indent(indent) << name << " : " << value.Get<bool>();
|
ss << Indent(indent) << name << " : " << value.Get<bool>();
|
||||||
} else {
|
} else {
|
||||||
ss << " " << value.Get<bool>() << " ";
|
ss << Indent(indent) << value.Get<bool>() << " ";
|
||||||
}
|
}
|
||||||
} else if (value.IsNumber()) {
|
} else if (value.IsNumber()) {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
ss << Indent(indent) << name << " : " << value.Get<double>();
|
ss << Indent(indent) << name << " : " << value.Get<double>();
|
||||||
} else {
|
} else {
|
||||||
ss << " " << value.Get<double>() << " ";
|
ss << Indent(indent) << value.Get<double>() << " ";
|
||||||
}
|
}
|
||||||
} else if (value.IsInt()) {
|
} else if (value.IsInt()) {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
ss << Indent(indent) << name << " : " << value.Get<int>();
|
ss << Indent(indent) << name << " : " << value.Get<int>();
|
||||||
} else {
|
} else {
|
||||||
ss << " " << value.Get<int>() << " ";
|
ss << Indent(indent) << value.Get<int>() << " ";
|
||||||
}
|
}
|
||||||
} else if (value.IsArray()) {
|
} 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++) {
|
for (size_t i = 0; i < value.Size(); i++) {
|
||||||
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
|
||||||
if (i != (value.ArrayLen() - 1)) {
|
if (i != (value.ArrayLen() - 1)) {
|
||||||
ss << ", ";
|
ss << ", \n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ss << Indent(indent) << "] ";
|
ss << "\n" << Indent(indent) << "] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo { binary }
|
// @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) {
|
static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
||||||
std::cout << Indent(indent) << "material : " << primitive.material
|
std::cout << Indent(indent) << "material : " << primitive.material
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@@ -326,17 +342,80 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
DumpStringIntMap(primitive.attributes, indent + 1);
|
DumpStringIntMap(primitive.attributes, indent + 1);
|
||||||
|
|
||||||
|
DumpExtensions(primitive.extensions, indent);
|
||||||
std::cout << Indent(indent) << "extras :" << std::endl
|
std::cout << Indent(indent) << "extras :" << std::endl
|
||||||
<< PrintValue("extras", primitive.extras, indent + 1) << 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) {
|
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
|
||||||
// TODO(syoyo): pritty print Value
|
const int indent) {
|
||||||
for (auto &e : extension) {
|
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
|
||||||
std::cout << Indent(indent) << e.first << std::endl;
|
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
|
||||||
std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
|
<< "\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) {
|
static void Dump(const tinygltf::Model &model) {
|
||||||
@@ -491,6 +570,21 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
std::cout << Indent(2)
|
std::cout << Indent(2)
|
||||||
<< "target : " << PrintTarget(bufferView.target)
|
<< "target : " << PrintTarget(bufferView.target)
|
||||||
<< std::endl;
|
<< 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,6 +595,21 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
std::cout << Indent(1) << "name : " << buffer.name << std::endl;
|
std::cout << Indent(1) << "name : " << buffer.name << std::endl;
|
||||||
std::cout << Indent(2) << "byteLength : " << buffer.data.size()
|
std::cout << Indent(2) << "byteLength : " << buffer.data.size()
|
||||||
<< std::endl;
|
<< 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,16 +618,55 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
for (size_t i = 0; i < model.materials.size(); i++) {
|
for (size_t i = 0; i < model.materials.size(); i++) {
|
||||||
const tinygltf::Material &material = model.materials[i];
|
const tinygltf::Material &material = model.materials[i];
|
||||||
std::cout << Indent(1) << "name : " << material.name << std::endl;
|
std::cout << Indent(1) << "name : " << material.name
|
||||||
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
|
|
||||||
<< std::endl;
|
<< 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 p(material.values.begin());
|
||||||
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
|
tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
|
||||||
for (; p != pEnd; p++) {
|
for (; p != pEnd; p++) {
|
||||||
std::cout << Indent(2) << p->first << ": "
|
std::cout << Indent(2) << p->first << ": "
|
||||||
<< PrintParameterValue(p->second) << std::endl;
|
<< 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,6 +690,18 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
std::cout << Indent(2) << "height : " << image.height << std::endl;
|
std::cout << Indent(2) << "height : " << image.height << std::endl;
|
||||||
std::cout << Indent(2) << "component : " << image.component << std::endl;
|
std::cout << Indent(2) << "component : " << image.component << std::endl;
|
||||||
DumpExtensions(image.extensions, 1);
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,6 +714,18 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
std::cout << Indent(1) << "source : " << texture.source
|
std::cout << Indent(1) << "source : " << texture.source
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
DumpExtensions(texture.extensions, 1);
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,6 +747,20 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
std::cout << Indent(2)
|
std::cout << Indent(2)
|
||||||
<< "wrapT : " << PrintWrapMode(sampler.wrapT)
|
<< "wrapT : " << PrintWrapMode(sampler.wrapT)
|
||||||
<< std::endl;
|
<< 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,6 +793,54 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
<< "znear : " << camera.orthographic.znear
|
<< "znear : " << camera.orthographic.znear
|
||||||
<< std::endl;
|
<< 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,6 +858,12 @@ int main(int argc, char **argv) {
|
|||||||
exit(1);
|
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::Model model;
|
||||||
tinygltf::TinyGLTF gltf_ctx;
|
tinygltf::TinyGLTF gltf_ctx;
|
||||||
std::string err;
|
std::string err;
|
||||||
@@ -631,6 +871,9 @@ int main(int argc, char **argv) {
|
|||||||
std::string input_filename(argv[1]);
|
std::string input_filename(argv[1]);
|
||||||
std::string ext = GetFilePathExtension(input_filename);
|
std::string ext = GetFilePathExtension(input_filename);
|
||||||
|
|
||||||
|
gltf_ctx.SetStoreOriginalJSONForExtrasAndExtensions(
|
||||||
|
store_original_json_for_extras_and_extensions);
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (ext.compare("glb") == 0) {
|
if (ext.compare("glb") == 0) {
|
||||||
std::cout << "Reading binary glTF" << std::endl;
|
std::cout << "Reading binary glTF" << std::endl;
|
||||||
|
|||||||
224
models/Cube-texture-ext/Cube-textransform.gltf
Normal file
224
models/Cube-texture-ext/Cube-textransform.gltf
Normal 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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
models/Cube-texture-ext/Cube.bin
Normal file
BIN
models/Cube-texture-ext/Cube.bin
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
models/Cube-texture-ext/Cube_MetallicRoughness.png
Normal file
BIN
models/Cube-texture-ext/Cube_MetallicRoughness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 319 B |
6
models/Cube-texture-ext/README.md
Normal file
6
models/Cube-texture-ext/README.md
Normal 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
|
||||||
|
|
||||||
BIN
models/CubeImageUriSpaces/ 2x2 image has multiple spaces.png
Normal file
BIN
models/CubeImageUriSpaces/ 2x2 image has multiple spaces.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 B |
BIN
models/CubeImageUriSpaces/2x2 image has spaces.png
Normal file
BIN
models/CubeImageUriSpaces/2x2 image has spaces.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 B |
171
models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf
Normal file
171
models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 2,
|
||||||
|
"POSITION": 1,
|
||||||
|
"TEXCOORD_0": 3
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorTexture": {
|
||||||
|
"index": 0,
|
||||||
|
"texCoord": 0
|
||||||
|
},
|
||||||
|
"baseColorFactor": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor": 1,
|
||||||
|
"roughnessFactor": 1
|
||||||
|
},
|
||||||
|
"emissiveFactor": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"alphaMode": "OPAQUE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"sampler": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"wrapS": 33071,
|
||||||
|
"wrapT": 33071
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"uri": " 2x2 image has multiple spaces.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5121,
|
||||||
|
"count": 36,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.5,
|
||||||
|
-0.5,
|
||||||
|
-0.5
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 3,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 36,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 324,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 612,
|
||||||
|
"byteLength": 192
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 804,
|
||||||
|
"uri": "CubeImageUriSpaces.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
models/CubeImageUriSpaces/CubeImageUriSpaces.bin
Normal file
BIN
models/CubeImageUriSpaces/CubeImageUriSpaces.bin
Normal file
Binary file not shown.
171
models/CubeImageUriSpaces/CubeImageUriSpaces.gltf
Normal file
171
models/CubeImageUriSpaces/CubeImageUriSpaces.gltf
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 2,
|
||||||
|
"POSITION": 1,
|
||||||
|
"TEXCOORD_0": 3
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorTexture": {
|
||||||
|
"index": 0,
|
||||||
|
"texCoord": 0
|
||||||
|
},
|
||||||
|
"baseColorFactor": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor": 1,
|
||||||
|
"roughnessFactor": 1
|
||||||
|
},
|
||||||
|
"emissiveFactor": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"alphaMode": "OPAQUE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"sampler": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"wrapS": 33071,
|
||||||
|
"wrapT": 33071
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"uri": "2x2 image has spaces.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5121,
|
||||||
|
"count": 36,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.5,
|
||||||
|
-0.5,
|
||||||
|
-0.5
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 3,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 36,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 324,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 612,
|
||||||
|
"byteLength": 192
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 804,
|
||||||
|
"uri": "CubeImageUriSpaces.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
46
tests/fuzzer/README.md
Normal file
46
tests/fuzzer/README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Fuzzing test
|
||||||
|
|
||||||
|
Do fuzzing test for TinyGLTF API.
|
||||||
|
|
||||||
|
## Supported API
|
||||||
|
|
||||||
|
* [x] LoadASCIIFromMemory
|
||||||
|
* [ ] LoadBinaryFromMemory
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* meson
|
||||||
|
* clang with fuzzer support(`-fsanitize=fuzzer`. at least clang 8.0 should work)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Ubuntu 18.04
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt install clang++-8
|
||||||
|
$ sudo apt install libfuzzer-8-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, if you didn't set `update-alternatives` you can set `clang++` to point to `clang++8`
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 10
|
||||||
|
$ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 10
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to compile
|
||||||
|
|
||||||
|
```
|
||||||
|
$ CXX=clang++ CC=clang meson build
|
||||||
|
$ cd build
|
||||||
|
$ ninja
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
Increase memory limit. e.g. `-rss_limit_mb=50000`
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./fuzz_gltf -rss_limit_mb=20000 -jobs 4
|
||||||
|
```
|
||||||
|
|
||||||
33
tests/fuzzer/fuzz_gltf.cc
Normal file
33
tests/fuzzer/fuzz_gltf.cc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
|
static void parse_intCoding4(const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
const char *str = reinterpret_cast<const char *>(data);
|
||||||
|
|
||||||
|
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, str, size, /* base_dir */"" );
|
||||||
|
(void)ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
int LLVMFuzzerTestOneInput(std::uint8_t const* data, std::size_t size)
|
||||||
|
{
|
||||||
|
parse_intCoding4(data, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
9
tests/fuzzer/meson.build
Normal file
9
tests/fuzzer/meson.build
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
project('fuzz_tinygltf', 'cpp', default_options : ['cpp_std=c++11'])
|
||||||
|
|
||||||
|
incdirs = include_directories('../../')
|
||||||
|
executable('fuzz_gltf',
|
||||||
|
'fuzz_gltf.cc',
|
||||||
|
include_directories : incdirs,
|
||||||
|
cpp_args : '-fsanitize=address,fuzzer',
|
||||||
|
link_args : '-fsanitize=address,fuzzer' )
|
||||||
|
|
||||||
122
tests/tester.cc
122
tests/tester.cc
@@ -13,6 +13,14 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
static JsonDocument JsonConstruct(const char* str)
|
||||||
|
{
|
||||||
|
JsonDocument doc;
|
||||||
|
JsonParse(doc, str, strlen(str));
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("parse-error", "[parse]") {
|
TEST_CASE("parse-error", "[parse]") {
|
||||||
|
|
||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
@@ -20,7 +28,7 @@ TEST_CASE("parse-error", "[parse]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
std::string warn;
|
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);
|
REQUIRE(false == ret);
|
||||||
|
|
||||||
@@ -167,12 +175,12 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
|
|||||||
SECTION("parses valid numbers") {
|
SECTION("parses valid numbers") {
|
||||||
std::string err;
|
std::string err;
|
||||||
int result = 123;
|
int result = 123;
|
||||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"zero", 0}}, "zero",
|
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"zero\" : 0}"), "zero",
|
||||||
true));
|
true));
|
||||||
REQUIRE(err == "");
|
REQUIRE(err == "");
|
||||||
REQUIRE(result == 0);
|
REQUIRE(result == 0);
|
||||||
|
|
||||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"int", -1234}}, "int",
|
CHECK(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": -1234}"), "int",
|
||||||
true));
|
true));
|
||||||
REQUIRE(err == "");
|
REQUIRE(err == "");
|
||||||
REQUIRE(result == -1234);
|
REQUIRE(result == -1234);
|
||||||
@@ -181,7 +189,7 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
|
|||||||
SECTION("detects missing properties") {
|
SECTION("detects missing properties") {
|
||||||
std::string err;
|
std::string err;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {}, "int", true));
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
|
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
|
||||||
REQUIRE(result == -1);
|
REQUIRE(result == -1);
|
||||||
}
|
}
|
||||||
@@ -190,7 +198,7 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
CHECK_FALSE(
|
CHECK_FALSE(
|
||||||
tinygltf::ParseIntegerProperty(&result, &err, {}, "int", false));
|
tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct(""), "int", false));
|
||||||
REQUIRE(err == "");
|
REQUIRE(err == "");
|
||||||
REQUIRE(result == -1);
|
REQUIRE(result == -1);
|
||||||
}
|
}
|
||||||
@@ -199,21 +207,26 @@ TEST_CASE("parse-integer", "[bounds-checking]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
|
|
||||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 0.5}},
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
|
||||||
"int", true));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
|
||||||
// Excessively large values and NaN aren't allowed either.
|
// Excessively large values and NaN aren't allowed either.
|
||||||
err.clear();
|
err.clear();
|
||||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 1e300}},
|
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
|
||||||
"int", true));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
|
||||||
err.clear();
|
err.clear();
|
||||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(
|
{
|
||||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
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));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +234,7 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
|
|||||||
SECTION("parses valid unsigned integers") {
|
SECTION("parses valid unsigned integers") {
|
||||||
// Use string-based parsing here, using the initializer list syntax doesn't
|
// Use string-based parsing here, using the initializer list syntax doesn't
|
||||||
// parse 0 as unsigned.
|
// parse 0 as unsigned.
|
||||||
json zero_obj = json::parse("{\"zero\": 0}");
|
auto zero_obj = JsonConstruct("{\"zero\": 0}");
|
||||||
|
|
||||||
std::string err;
|
std::string err;
|
||||||
size_t result = 123;
|
size_t result = 123;
|
||||||
@@ -235,26 +248,31 @@ TEST_CASE("parse-unsigned", "[bounds-checking]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
size_t result = -1;
|
size_t result = -1;
|
||||||
|
|
||||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", -1234}},
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": -1234}"),
|
||||||
"int", true));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
err.clear();
|
err.clear();
|
||||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 0.5}},
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 0.5}"),
|
||||||
"int", true));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
// Excessively large values and NaN aren't allowed either.
|
// Excessively large values and NaN aren't allowed either.
|
||||||
err.clear();
|
err.clear();
|
||||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 1e300}},
|
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, JsonConstruct("{\"int\": 1e300}"),
|
||||||
"int", true));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
|
||||||
err.clear();
|
err.clear();
|
||||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
|
{
|
||||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
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));
|
"int", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +281,7 @@ TEST_CASE("parse-integer-array", "[bounds-checking]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
std::vector<int> result;
|
std::vector<int> result;
|
||||||
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
|
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
|
||||||
{{"x", {-1, 2, 3}}}, "x", true));
|
JsonConstruct("{\"x\": [-1, 2, 3]}"), "x", true));
|
||||||
REQUIRE(err == "");
|
REQUIRE(err == "");
|
||||||
REQUIRE(result.size() == 3);
|
REQUIRE(result.size() == 3);
|
||||||
REQUIRE(result[0] == -1);
|
REQUIRE(result[0] == -1);
|
||||||
@@ -275,7 +293,69 @@ TEST_CASE("parse-integer-array", "[bounds-checking]") {
|
|||||||
std::string err;
|
std::string err;
|
||||||
std::vector<int> result;
|
std::vector<int> result;
|
||||||
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
|
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
|
||||||
&result, &err, {{"x", {-1, 1e300, 3}}}, "x", true));
|
&result, &err, JsonConstruct("{\"x\": [-1, 1e300, 3]}"), "x", true));
|
||||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("image-uri-spaces", "[issue-236]") {
|
||||||
|
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
// Test image file with single spaces.
|
||||||
|
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf");
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
|
||||||
|
// Test image file with a beginning space, trailing space, and greater than
|
||||||
|
// one consecutive spaces.
|
||||||
|
ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf");
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
4125
tiny_gltf.h
4125
tiny_gltf.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user