Compare commits

..

11 Commits

Author SHA1 Message Date
Syoyo Fujita
3c0bcb7d72 Add document on schema validation feature. 2019-06-24 15:30:32 +09:00
Syoyo Fujita
d5694dc15d Some pointer variables are not initialized. 2019-06-15 16:22:40 +09:00
Syoyo Fujita
ddf0a0e83c Update rapidjson-amalgamation to include error/en.h and cursorstreamwrapper.h.
Now schema validation is getting to work.
2019-06-14 22:03:11 +09:00
Syoyo Fujita
f3ee08c595 Merge branch 'rapidjson' of github.com:syoyo/tinygltf into rapidjson 2019-06-14 19:29:26 +09:00
Syoyo Fujita
f75327bc5b Fix compilation on MSVC. 2019-06-14 19:29:13 +09:00
Syoyo Fujita
7acc95a2ae Write an array of string to avoid the limit of the character length in MSVC compiler. 2019-06-14 19:28:37 +09:00
Syoyo Fujita
2a6f2cc356 Serializer now started to work. 2019-06-13 20:36:37 +09:00
Syoyo Fujita
0cf2812775 Use rapidjson for serialization(W.I.P. currently segfaults when serialize a scene) 2019-06-12 22:35:28 +09:00
Syoyo Fujita
2673d1d3ef Add C++ string of glTF Schema. 2019-06-11 14:38:01 +09:00
Syoyo Fujita
cf8b7cc0a4 Add JSON schema ref resolver. 2019-06-11 14:25:16 +09:00
Syoyo Fujita
93d0e365bb RapidJson version of TinyGLTF.
TODO: Serializer.
2019-06-10 02:39:13 +09:00
37 changed files with 21956 additions and 6102 deletions

View File

@@ -1,165 +0,0 @@
name: C/C++ CI
on: [push, pull_request]
jobs:
# compile with older gcc4.8
build-gcc48:
runs-on: ubuntu-18.04
name: Build with gcc 4.8
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-4.8 g++-4.8
g++-4.8 -std=c++11 -o loader_example loader_example.cc
- name: NoexceptBuild
run: |
g++-4.8 -DTINYGLTF_NOEXCEPTION -std=c++11 -o loader_example loader_example.cc
- name: RapidjsonBuild
run: |
git clone https://github.com/Tencent/rapidjson
g++-4.8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
# compile with mingw gcc cross
build-mingw-cross:
runs-on: ubuntu-18.04
name: Build with MinGW gcc cross
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y mingw-w64
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
# Windows(x64) + Visual Studio 2019 build
build-windows-msvc:
runs-on: windows-latest
name: Build for Windows(x64, MSVC)
# Use system installed cmake
# https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Configure
run: |
mkdir build
cd build
cmake -G "Visual Studio 16 2019" -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
cd ..
- name: Build
run: cmake --build build --config Release
build-linux:
runs-on: ubuntu-latest
name: Buld with gcc
steps:
- uses: actions/checkout@v2
- name: build
run: |
g++ -std=c++11 -o loader_example loader_example.cc
- name: test
run: |
./loader_example models/Cube/Cube.gltf
- name: tests
run: |
cd tests
g++ -I../ -std=c++11 -g -O0 -o tester tester.cc
./tester
cd ..
- name: noexcept_tests
run: |
cd tests
g++ -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
./tester_noexcept
cd ..
build-rapidjson-linux:
runs-on: ubuntu-latest
name: Buld with gcc + rapidjson
steps:
- uses: actions/checkout@v2
- name: build
run: |
git clone https://github.com/Tencent/rapidjson
g++ -v
g++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -o loader_example loader_example.cc
- name: loader_example_test
run: |
./loader_example models/Cube/Cube.gltf
- name: tests
run: |
cd tests
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -I../ -std=c++11 -g -O0 -o tester tester.cc
./tester
cd ..
- name: noexcept_tests
run: |
cd tests
g++ -DTINYGLTF_USE_RAPIDJSON -I../rapidjson/include/rapidjson -DTINYGLTF_NOEXCEPTION -I../ -std=c++11 -g -O0 -o tester_noexcept tester.cc
./tester_noexcept
cd ..
# Cross-compile for aarch64 linux target
build-cross-aarch64:
runs-on: ubuntu-18.04
name: Build on cross aarch64
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Build
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install -y gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu
git clone https://github.com/Tencent/rapidjson
aarch64-linux-gnu-g++-8 -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc
# macOS clang
build-macos:
runs-on: macos-latest
name: Build on macOS
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Build
run: |
clang++ -std=c++11 -g -O0 -o loader_example loader_example.cc
./loader_example models/Cube/Cube.gltf
git clone https://github.com/Tencent/rapidjson
clang++ -DTINYGLTF_USE_RAPIDJSON -I./rapidjson/include/rapidjson -std=c++11 -g -O0 -o loader_example loader_example.cc

1
.gitignore vendored
View File

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

View File

@@ -31,17 +31,6 @@ 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
@@ -53,11 +42,6 @@ script:
- ${CC} -v - ${CC} -v
- ${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 examples/raytrace
- clang++ -v
- make
- ./tester
- ./tester_noexcept
- cd ../examples/raytrace
- ../../premake5 gmake - ../../premake5 gmake
- make - make

View File

@@ -4,27 +4,14 @@ PROJECT (tinygltf)
SET(CMAKE_CXX_STANDARD 11) SET(CMAKE_CXX_STANDARD 11)
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example" ON) ADD_EXECUTABLE ( loader_example
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF) loader_example.cc
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF) )
if (TINYGLTF_BUILD_LOADER_EXAMPLE) ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_EXECUTABLE ( loader_example ADD_SUBDIRECTORY ( examples/glview )
loader_example.cc ADD_SUBDIRECTORY ( examples/validator )
)
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
if (TINYGLTF_BUILD_GL_EXAMPLES)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
endif (TINYGLTF_BUILD_GL_EXAMPLES)
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
ADD_SUBDIRECTORY ( examples/validator )
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
#
# 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

13
LICENSE.rapidjson.txt Normal file
View File

@@ -0,0 +1,13 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

View File

@@ -2,13 +2,11 @@
`TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library. `TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library.
`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler. `TinyGLTF` uses single-header version of RapidJson(https://github.com/Tencent/rapidjson) as a JSON parser.
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 release(Support built-in schema validation)
- 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)!
@@ -19,8 +17,6 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
[![Build status](https://ci.appveyor.com/api/projects/status/warngenu9wjjhlm8?svg=true)](https://ci.appveyor.com/project/syoyo/tinygltf) [![Build status](https://ci.appveyor.com/api/projects/status/warngenu9wjjhlm8?svg=true)](https://ci.appveyor.com/project/syoyo/tinygltf)
![C/C++ CI](https://github.com/syoyo/tinygltf/workflows/C/C++%20CI/badge.svg)
## Features ## Features
* Written in portable C++. C++-11 with STL dependency only. * Written in portable C++. C++-11 with STL dependency only.
@@ -36,11 +32,9 @@ 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] Load * [x] PBR material description
* [x] Save(.bin embedded .glb) * [x] Validate inpit glTF JSON with schema
* 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.
@@ -60,13 +54,6 @@ 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
@@ -80,14 +67,13 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR * Physical based rendering with Vulkan using glTF 2.0 models https://github.com/SaschaWillems/Vulkan-glTF-PBR
* GLTF loader plugin for OGRE 2.1. Support for PBR materials via HLMS/PBS https://github.com/Ybalrid/Ogre_glTF * 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
* 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.
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
* Your projects here! (Please send PR) * Your projects here! (Please send PR)
## For developer
Generate single rapidjson file using this node.js script: https://github.com/Tencent/rapidjson/issues/863
Add `cursorstreamwrapper.h` and `error/en.h` inclusion in `rapidjson-all.h` before running merge script.
## TODOs ## TODOs
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing. * [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
@@ -95,7 +81,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [x] Load Draco compressed mesh * [x] Load Draco compressed mesh
* [ ] Save Draco compressed mesh * [ ] Save Draco compressed mesh
* [ ] Open3DGC? * [ ] Open3DGC?
* [x] Support `extensions` and `extras` property * [ ] 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
@@ -115,7 +101,7 @@ TinyGLTF uses the following third party libraries.
## Build and example ## Build and example
Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project. Copy `stb_image.h`, `stb_image_write.h`, `rapidjson-amalgamation.h` and `tiny_gltf.h` to your project.
### Loading glTF 2.0 model ### Loading glTF 2.0 model
@@ -124,6 +110,7 @@ Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your pr
#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_ENABLE_SCHEMA_VALIDATOR // optional. enable schema validation API.
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling. // #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
#include "tiny_gltf.h" #include "tiny_gltf.h"
@@ -136,6 +123,10 @@ std::string warn;
bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]); bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]);
//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb) //bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb)
// Validate with glTF Schema
// #if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
// bool ret = loader.LoadASCIIFromFileWithValidation(&model, &err, &warn, argv[1]);
// #endif
if (!warn.empty()) { if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str()); printf("Warn: %s\n", warn.c_str());
@@ -153,6 +144,7 @@ if (!ret) {
## Compile options ## Compile options
* `TINYGLTF_ENABLE_SCHEMA_VALIDATOR` : Enable API with schema validation. glTF Schema JSON(`gltf.schema.resolved.inc`) are embeded into application binary, thus no need to read glTF Schema file at a runtime.
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF. * `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images. * `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images. * `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
@@ -162,22 +154,17 @@ 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.
@@ -205,17 +192,8 @@ $ ./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

View File

@@ -19,7 +19,3 @@ $ make
Plese use solution file located at `basic` folder. Plese use solution file located at `basic` folder.
## Limitation
There are so many limitations in this example(e.g. no PBR shader. the shader only shows texture of textures[0] if available).

View File

@@ -1,378 +1,365 @@
#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).
*/ */
} }
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer]; 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;
} }
if (model.textures.size() > 0) { GLuint texid;
// fixme: Use material's baseColor glGenTextures(1, &texid);
tinygltf::Texture &tex = model.textures[0];
tinygltf::Texture &tex = model.textures[0];
if (tex.source > -1) { tinygltf::Image &image = model.images[tex.source];
GLuint texid; glBindTexture(GL_TEXTURE_2D, texid);
glGenTextures(1, &texid); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
tinygltf::Image &image = model.images[tex.source]; glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GLenum format = GL_RGBA;
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); if (image.component == 1) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); format = GL_RED;
} else if (image.component == 2) {
GLenum format = GL_RGBA; format = GL_RG;
} else if (image.component == 3) {
if (image.component == 1) { format = GL_RGB;
format = GL_RED; } else {
} else if (image.component == 2) { // ???
format = GL_RG; }
} else if (image.component == 3) {
format = GL_RGB; GLenum type = GL_UNSIGNED_BYTE;
} else { if (image.bits == 8) {
// ??? // ok
} } else if (image.bits == 16) {
type = GL_UNSIGNED_SHORT;
GLenum type = GL_UNSIGNED_BYTE; } else {
if (image.bits == 8) { // ???
// ok }
} else if (image.bits == 16) {
type = GL_UNSIGNED_SHORT; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
} else { format, type, &image.image.at(0));
// ??? }
}
return vbos;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, }
format, type, &image.image.at(0));
} // bind models
} void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
} tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]);
return vbos; for (size_t i = 0; i < node.children.size(); i++) {
} bindModelNodes(vbos, model, model.nodes[node.children[i]]);
}
// bind models }
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, GLuint bindModel(tinygltf::Model &model) {
tinygltf::Node &node) { std::map<int, GLuint> vbos;
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) { GLuint vao;
bindMesh(vbos, model, model.meshes[node.mesh]); glGenVertexArrays(1, &vao);
} glBindVertexArray(vao);
for (size_t i = 0; i < node.children.size(); i++) { const tinygltf::Scene &scene = model.scenes[model.defaultScene];
assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size())); for (size_t i = 0; i < scene.nodes.size(); ++i) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]); bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
} }
}
GLuint bindModel(tinygltf::Model &model) { glBindVertexArray(0);
std::map<int, GLuint> vbos; // cleanup vbos
GLuint vao; for (size_t i = 0; i < vbos.size(); ++i) {
glGenVertexArrays(1, &vao); glDeleteBuffers(1, &vbos[i]);
glBindVertexArray(vao); }
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; return vao;
for (size_t i = 0; i < scene.nodes.size(); ++i) { }
assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]); void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
} for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
glBindVertexArray(0); tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
// cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) { glDrawElements(primitive.mode, indexAccessor.count,
glDeleteBuffers(1, &vbos[i]); indexAccessor.componentType,
} BUFFER_OFFSET(indexAccessor.byteOffset));
}
return vao; }
}
// recursively draw node and children nodes of model
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) { void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) { drawMesh(model, model.meshes[node.mesh]);
tinygltf::Primitive primitive = mesh.primitives[i]; for (size_t i = 0; i < node.children.size(); i++) {
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; drawModelNodes(model, model.nodes[node.children[i]]);
}
glDrawElements(primitive.mode, indexAccessor.count, }
indexAccessor.componentType, void drawModel(GLuint vao, tinygltf::Model &model) {
BUFFER_OFFSET(indexAccessor.byteOffset)); glBindVertexArray(vao);
}
} const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
// recursively draw node and children nodes of model drawModelNodes(model, model.nodes[scene.nodes[i]]);
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) { }
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
drawMesh(model, model.meshes[node.mesh]); glBindVertexArray(0);
} }
for (size_t i = 0; i < node.children.size(); i++) {
drawModelNodes(model, model.nodes[node.children[i]]); void dbgModel(tinygltf::Model &model) {
} for (auto &mesh : model.meshes) {
} std::cout << "mesh : " << mesh.name << std::endl;
void drawModel(GLuint vao, tinygltf::Model &model) { for (auto &primitive : mesh.primitives) {
glBindVertexArray(vao); const tinygltf::Accessor &indexAccessor =
model.accessors[primitive.indices];
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) { std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
drawModelNodes(model, model.nodes[scene.nodes[i]]); << indexAccessor.componentType << std::endl;
}
tinygltf::Material &mat = model.materials[primitive.material];
glBindVertexArray(0); for (auto &mats : mat.values) {
} std::cout << "mat : " << mats.first.c_str() << std::endl;
}
void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) { for (auto &image : model.images) {
std::cout << "mesh : " << mesh.name << std::endl; std::cout << "image name : " << image.uri << std::endl;
for (auto &primitive : mesh.primitives) { std::cout << " size : " << image.image.size() << std::endl;
const tinygltf::Accessor &indexAccessor = std::cout << " w/h : " << image.width << "/" << image.height
model.accessors[primitive.indices]; << std::endl;
}
std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl; std::cout << "indices : " << primitive.indices << std::endl;
std::cout << "mode : "
tinygltf::Material &mat = model.materials[primitive.material]; << "(" << primitive.mode << ")" << std::endl;
for (auto &mats : mat.values) {
std::cout << "mat : " << mats.first.c_str() << std::endl; for (auto &attrib : primitive.attributes) {
} std::cout << "attribute : " << attrib.first.c_str() << std::endl;
}
for (auto &image : model.images) { }
std::cout << "image name : " << image.uri << std::endl; }
std::cout << " size : " << image.image.size() << std::endl; }
std::cout << " w/h : " << image.width << "/" << image.height
<< std::endl; glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
} // Camera matrix
glm::mat4 view = glm::lookAt(
std::cout << "indices : " << primitive.indices << std::endl; pos, // Camera in World Space
std::cout << "mode : " lookat, // and looks at the origin
<< "(" << primitive.mode << ")" << std::endl; glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
for (auto &attrib : primitive.attributes) {
std::cout << "attribute : " << attrib.first.c_str() << std::endl; return view;
} }
}
} glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
} int h) {
glm::mat4 Projection =
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) { glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
// Camera matrix
glm::mat4 view = glm::lookAt( // Or, for an ortho camera :
pos, // Camera in World Space // glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
lookat, // and looks at the origin // // In world coordinates
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
); glm::mat4 mvp = Projection * view_mat * model_mat;
return view; return mvp;
} }
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w, void displayLoop(Window &window, const std::string &filename) {
int h) { Shaders shader = Shaders();
glm::mat4 Projection = glUseProgram(shader.pid);
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
// grab uniforms to modify
// Or, for an ortho camera : GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
// // In world coordinates GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
glm::mat4 mvp = Projection * view_mat * model_mat; tinygltf::Model model;
if (!loadModel(model, filename.c_str())) return;
return mvp;
} GLuint vao = bindModel(model);
// dbgModel(model); return;
void displayLoop(Window &window, const std::string &filename) {
Shaders shader = Shaders(); // Model matrix : an identity matrix (model will be at the origin)
glUseProgram(shader.pid); glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f);
// grab uniforms to modify glm::vec3 model_pos = glm::vec3(-3, 0, -3);
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position"); // generate a camera view, based on eye-position and lookAt world-position
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color"); glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
tinygltf::Model model; glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
if (!loadModel(model, filename.c_str())) return; glm::vec3 sun_color = glm::vec3(1.0);
GLuint vao = bindModel(model); while (!window.Close()) {
// dbgModel(model); return; window.Resize();
// Model matrix : an identity matrix (model will be at the origin) glClearColor(0.2, 0.2, 0.2, 1.0);
glm::mat4 model_mat = glm::mat4(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3 model_pos = glm::vec3(-3, 0, -3); glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model
// generate a camera view, based on eye-position and lookAt world-position model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos); glm::vec3(0, 1, 0)); // rotate model on y axis
model_mat = trans * model_rot;
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
glm::vec3 sun_color = glm::vec3(1.0); // build a model-view-projection
GLint w, h;
while (!window.Close()) { glfwGetWindowSize(window.window, &w, &h);
window.Resize(); glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUniform3fv(sun_position_u, 1, &sun_position[0]);
glUniform3fv(sun_color_u, 1, &sun_color[0]);
glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model drawModel(vao, model);
model_rot = glm::rotate(model_rot, glm::radians(0.8f), glfwSwapBuffers(window.window);
glm::vec3(0, 1, 0)); // rotate model on y axis glfwPollEvents();
model_mat = trans * model_rot; }
}
// build a model-view-projection
GLint w, h; static void error_callback(int error, const char *description) {
glfwGetWindowSize(window.window, &w, &h); (void)error;
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h); fprintf(stderr, "Error: %s\n", description);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]); }
glUniform3fv(sun_position_u, 1, &sun_position[0]); int main(int argc, char **argv) {
glUniform3fv(sun_color_u, 1, &sun_color[0]); std::string filename = "../../models/Cube/Cube.gltf";
drawModel(vao, model); if (argc > 1) {
glfwSwapBuffers(window.window); filename = argv[1];
glfwPollEvents(); }
}
} glfwSetErrorCallback(error_callback);
static void error_callback(int error, const char *description) { if (!glfwInit()) return -1;
(void)error;
fprintf(stderr, "Error: %s\n", description); // Force create OpenGL 3.3
} // NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
int main(int argc, char **argv) { glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
std::string filename = "../../models/Cube/Cube.gltf"; glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
if (argc > 1) { glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
filename = argv[1]; #endif
} #endif
glfwSetErrorCallback(error_callback); Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window);
if (!glfwInit()) return -1;
#ifdef __APPLE__
// Force create OpenGL 3.3 // https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work. glewExperimental = GL_TRUE;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); #endif
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glewInit();
#ifdef __APPLE__ std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); << std::endl;
#endif
if (!GLEW_VERSION_3_3) {
Window window = Window(800, 600, "TinyGLTF basic example"); std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
glfwMakeContextCurrent(window.window); return EXIT_FAILURE;
}
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault glEnable(GL_DEPTH_TEST);
glewExperimental = GL_TRUE; glDepthFunc(GL_LESS);
#endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glewInit(); glEnable(GL_BLEND);
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl; displayLoop(window, filename);
if (!GLEW_VERSION_3_3) { glfwTerminate();
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl; return 0;
return EXIT_FAILURE; }
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}

16
gltf.schema.resolved.inc Normal file

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@
// TODO(syoyo): Print extensions and extras for each glTF object. // TODO(syoyo): Print extensions and extras for each glTF object.
// //
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#define TINYGLTF_ENABLE_SCHEMA_VALIDATOR
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h" #include "tiny_gltf.h"
@@ -175,10 +176,7 @@ 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]; ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -193,10 +191,7 @@ 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]; ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -249,36 +244,35 @@ 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 << Indent(indent) << value.Get<std::string>() << " "; ss << " " << 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 << Indent(indent) << value.Get<bool>() << " "; ss << " " << 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 << Indent(indent) << value.Get<double>() << " "; ss << " " << 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 << Indent(indent) << value.Get<int>() << " "; ss << " " << value.Get<int>() << " ";
} }
} else if (value.IsArray()) { } else if (value.IsArray()) {
// TODO(syoyo): Better pretty printing of array item ss << Indent(indent) << name << " [ ";
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 << ", \n"; ss << ", ";
} }
} }
ss << "\n" << Indent(indent) << "] "; ss << Indent(indent) << "] ";
} }
// @todo { binary } // @todo { binary }
@@ -322,15 +316,6 @@ 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;
@@ -342,80 +327,17 @@ 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,
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo, const int indent) {
const int indent) { // TODO(syoyo): pritty print Value
std::cout << Indent(indent) << "index : " << texinfo.index << "\n"; for (auto &e : extension) {
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord std::cout << Indent(indent) << e.first << std::endl;
<< "\n"; std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
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) {
@@ -570,21 +492,6 @@ 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";
}
} }
} }
@@ -595,21 +502,6 @@ 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";
}
} }
} }
@@ -618,55 +510,16 @@ 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::cout << Indent(1) << "name : " << material.name << 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::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl; << 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";
}
} }
} }
@@ -690,18 +543,6 @@ 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";
}
} }
} }
@@ -714,18 +555,6 @@ 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";
}
} }
} }
@@ -747,20 +576,6 @@ 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";
}
} }
} }
@@ -793,54 +608,6 @@ 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";
}
} }
} }
@@ -858,12 +625,6 @@ 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;
@@ -871,9 +632,6 @@ 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;
@@ -883,8 +641,13 @@ int main(int argc, char **argv) {
} else { } else {
std::cout << "Reading ASCII glTF" << std::endl; std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF. // assume ascii glTF.
#if defined(TINYGLTF_ENABLE_SCHEMA_VALIDATOR)
ret =
gltf_ctx.LoadASCIIFromFileWithValidation(&model, &err, &warn, input_filename.c_str());
#else
ret = ret =
gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
#endif
} }
if (!warn.empty()) { if (!warn.empty()) {

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 B

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

View File

@@ -1,6 +0,0 @@
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

View File

@@ -1,171 +0,0 @@
{
"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"
}
]
}

View File

@@ -1,171 +0,0 @@
{
"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"
}
]
}

View File

@@ -1,376 +0,0 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 8,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5125,
"count": 36,
"type": "SCALAR"
}
],
"asset": {
"copyright": "NVIDIA Corporation",
"generator": "Iray glTF plugin",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 96,
"byteStride": 12
},
{
"buffer": 0,
"byteLength": 144,
"byteOffset": 96
}
],
"buffers": [
{
"byteLength": 240,
"uri": "issue-261.bin"
}
],
"cameras": [
{
"extensions": {
"NV_Iray": {
"mip_burn_highlights": 0.699999988079071,
"mip_burn_highlights_per_component": false,
"mip_camera_shutter": 4.0,
"mip_cm2_factor": 1.0,
"mip_crush_blacks": 0.5,
"mip_f_number": 1.0,
"mip_film_iso": 100.0,
"mip_gamma": 2.200000047683716,
"mip_saturation": 1.0,
"mip_vignetting": 0.00019999999494757503,
"mip_whitepoint": [
1.0,
1.0,
1.0,
1.0
],
"tm_enable_tonemapper": true,
"tm_tonemapper": "mia_exposure_photographic"
}
},
"extras": {
"resolution": [
640,
480
]
},
"name": "default",
"perspective": {
"aspectRatio": 1.3333333730697632,
"yfov": 0.9272952079772949,
"zfar": 1000.0,
"znear": 0.1
},
"type": "perspective"
}
],
"extensions": {
"KHR_lights_punctual": {
"lights": [
{
"color": [
1.0,
1.0,
1.0
],
"intensity": 1000.0,
"name": "light",
"type": "point"
}
]
},
"NV_MDL": {
"modules": [
"mdl::base",
"mdl::nvidia::core_definitions",
"mdl::state"
],
"shaders": [
{
"definition": "mdl::base::environment_spherical(texture_2d)",
"name": "env_shd"
},
{
"arguments": {
"base_color": [
0.0055217444896698,
0.36859095096588135,
0.0041161770932376385
],
"normal=": 2
},
"definition": "mdl::nvidia::core_definitions::flex_material",
"name": "cube_instance_material"
},
{
"definition": "mdl::state::normal()",
"name": "mdl::state::normal_341"
},
{
"arguments": {
"base_color": [
0.0055217444896698,
0.36859095096588135,
0.0041161770932376385
],
"normal=": 4
},
"definition": "mdl::nvidia::core_definitions::flex_material",
"name": "cube_instance_material"
},
{
"definition": "mdl::state::normal()",
"name": "mdl::state::normal_341"
}
]
}
},
"extensionsUsed": [
"NV_MDL",
"NV_Iray",
"KHR_lights_punctual"
],
"materials": [
{
"doubleSided": true,
"extras": {
"mdl_shader": 1
},
"name": "cube_instance_material",
"pbrMetallicRoughness": {
"baseColorFactor": [
0.0055217444896698,
0.36859095096588135,
0.0041161770932376385,
1.0
]
}
}
],
"meshes": [
{
"name": "cube",
"primitives": [
{
"attributes": {
"POSITION": 0
},
"indices": 1,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"camera": 0,
"extensions": {
"NV_Iray": {
"iview:fkey": -1,
"iview:fov": 53.130104064941406,
"iview:interest": [
0.1342654824256897,
-0.14356137812137604,
0.037264324724674225
],
"iview:position": [
0.9729073643684387,
1.2592438459396362,
2.4199187755584717
],
"iview:roll": 0.0,
"iview:up": [
0.0,
1.0,
0.0
]
}
},
"matrix": [
0.9432751389105357,
-1.1769874756875739e-16,
-0.3320120665176343,
0.0,
-0.16119596696756341,
0.8742297945345237,
-0.45797175303889276,
0.0,
0.290254840694694,
0.48551237507207207,
0.8246392308792816,
0.0,
0.9729073377709113,
1.2592438262175363,
2.419918748461627,
1.0
],
"name": "CamInst"
},
{
"extensions": {
"NV_Iray": {
"caustic": true,
"caustic_cast": true,
"caustic_recv": true,
"face_back": true,
"face_front": true,
"finalgather": true,
"finalgather_cast": true,
"finalgather_recv": true,
"globillum": true,
"globillum_cast": true,
"globillum_recv": true,
"material=": 3,
"pickable": true,
"reflection_cast": true,
"reflection_recv": true,
"refraction_cast": true,
"refraction_recv": true,
"shadow_cast": true,
"shadow_recv": true,
"transparency_cast": true,
"transparency_recv": true,
"visible": true
}
},
"mesh": 0,
"name": "cube_instance"
},
{
"extensions": {
"KHR_lights_punctual": {
"light": 0
},
"NV_Iray": {
"shadow_cast": true,
"visible": false
}
},
"matrix": [
0.6988062355563571,
-7.76042172309776e-17,
-0.7153110128800992,
-0.0,
-0.4276881690736487,
0.8015668284138362,
-0.41781987700564616,
-0.0,
0.57336957992379,
0.5979051928078428,
0.5601398979107212,
0.0,
2.3640632834071384,
2.465226204472449,
2.309515908392224,
1.0
],
"name": "light_inst"
}
],
"scene": 0,
"scenes": [
{
"extensions": {
"NV_Iray": {
"CP_canny_threshold1": 40,
"CP_canny_threshold2": 120,
"CP_color_quantization": 8,
"IVP_color": [
1.0,
0.0,
0.0,
1.0
],
"TM_drago_bias": 0.8500000238418579,
"TM_drago_gamma2": 2.200000047683716,
"TM_drago_saturation": 1.0,
"TM_durand_contrast": 4.0,
"TM_durand_gamma": 2.200000047683716,
"TM_durand_saturation": 1.0,
"TM_durand_sigma_color": 2.0,
"TM_durand_sigma_space": 2.0,
"TM_linear_gamma": 2.200000047683716,
"TM_reinhard_color_adapt": 0.8999999761581421,
"TM_reinhard_gamma": 1.0,
"TM_reinhard_intensity": 0.0,
"TM_reinhard_light_adapt": 1.0,
"TM_reye_Ywhite": 1000000.0,
"TM_reye_bsize": 2,
"TM_reye_bthres": 3.0,
"TM_reye_gamma": 2.200000047683716,
"TM_reye_key": 0.5,
"TM_reye_saturation": 1.0,
"TM_reye_whitebalance": [
1.0,
0.9965101480484009,
0.9805564880371094,
0.0
],
"environment_dome_depth": 200.0,
"environment_dome_height": 200.0,
"environment_dome_mode": "infinite",
"environment_dome_position": [
0.0,
0.0,
0.0
],
"environment_dome_radius": 100.0,
"environment_dome_rotation_angle": 0.0,
"environment_dome_width": 200.0,
"environment_function=": 0,
"environment_function_intensity": 1.9900000095367432,
"iray_instancing": "off",
"iview::inline_color": [
1.0,
0.0,
0.0,
1.0
],
"iview::inline_width": 1.0,
"iview::magnifier_size": 300,
"iview::offset": 10.0,
"iview::outline_color": [
0.0,
0.0,
0.0,
1.0
],
"iview::outline_width": 2.0,
"iview::overview": true,
"iview::zoom_factor": 1.0,
"samples": 4.0,
"shadow_cast": true,
"shadow_recv": true
}
},
"nodes": [
0,
1,
2
]
}
]
}

16906
rapidjson-amalgamation.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +0,0 @@
# 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
```

View File

@@ -1,33 +0,0 @@
#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;
}

View File

@@ -1,9 +0,0 @@
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' )

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
Create single schema string by deferencing $ref in glTF schema JSON for embedding JSON scheme string in C++.
## Setup
Use python2
```
$ pip2 install jsonpath-rw
$ pip2 install simplejson
```
Put `ref_resolver.py` and `generate_single_schema_doc.py` to glTF schema direcotry(i.e. `$glTF/specification/2.0/schema`)
## Generate
Run `generate_single_schema_doc.py`
## TODO
* [ ] Print date and git commit id?

View File

@@ -0,0 +1,37 @@
# for print with `end` parameter
from __future__ import print_function
import json
from ref_resolver import RefResolver
import base64
f = open("glTF.schema.json")
j = json.loads(f.read())
# call to API resolve method
RefResolver("glTF.schema.json").resolve(j)
j_str = json.dumps(j, indent=2)
# Run json.dumps twice to get escaped string
escaped_str = json.dumps(j_str)
# MSVC does not accept string larger than 16K.
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=vs-2019
# Also, it has a hard limit of 65,535 bytes even splitting a string with double quotation.
# So, we write string as an array of string(then application must concatenate it)
# https://stackoverflow.com/questions/9475241/split-string-every-nth-character
n = 8000 # Conservative number
splitted_string = [escaped_str[i:i+n] for i in range(0, len(escaped_str), n)]
#print(len(splitted_string))
print("const char *kglTFSchemaStrings[] = {", end='')
for (i, s) in enumerate(splitted_string):
print(s, end='')
if i != (len(splitted_string) - 1):
print('",\n"', end='')
print("};")

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from urlparse import urlparse, urljoin
import simplejson as json
from os.path import isfile
import jsonpath_rw
import requests
cache = {}
class RefResolver:
def __init__(self):
self.url_fragments = None
def __init__(self, id):
self.id = id
if id is not None:
self.url_fragments = urlparse(id)
else:
self.url_fragments = None
def resolve(self, json_obj):
if isinstance(json_obj, dict):
for key, value in json_obj.items():
if key == "$ref":
ref_frag = urlparse(value)
ref_file = ref_frag.netloc + ref_frag.path
json_dump = {}
if ref_file in cache:
json_dump = cache[ref_file]
else:
if self.url_fragments.scheme in ['http', 'https']:
ref_url = urljoin(self.id, ref_file)
if callable(requests.Response.json):
json_dump = requests.get(ref_url).json()
else:
json_dump = requests.get(ref_url).json
ref_id = None
if 'tilte' in json_dump:
ref_id = json_dump['title']
cache[ref_file] = json_dump
RefResolver(ref_id).resolve(json_dump)
cache[ref_file] = json_dump
#elif self.url_fragments.scheme == 'file':
else:
if isfile(ref_file):
# if the ref is another file -> go there and get it
json_dump = json.load(open(ref_file))
ref_id = None
if 'title' in json_dump:
ref_id = json_dump['title']
cache[ref_file] = json_dump
RefResolver(ref_id).resolve(json_dump)
cache[ref_file] = json_dump
else:
# if the ref is in the same file grab it from the same file
json_dump = json.load(open(self.url_fragments.netloc+self.url_fragments.path))
cache[ref_file] = json_dump
ref_path_expr = "$" + ".".join(ref_frag.fragment.split("/"))
path_expression = jsonpath_rw.parse(ref_path_expr)
list_of_values = [match.value for match in path_expression.find(json_dump)]
if len(list_of_values) > 0:
resolution = list_of_values[0]
return resolution
resolved = self.resolve(value)
if resolved is not None:
json_obj[key] = resolved
elif isinstance(json_obj, list):
for (key, value) in enumerate(json_obj):
resolved = self.resolve(value)
if resolved is not None:
json_obj[key] = resolved
return None