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
52 changed files with 21984 additions and 8170 deletions

View File

@@ -1 +0,0 @@
blank_issues_enabled: false

View File

@@ -1,30 +0,0 @@
---
name: Issue report
about: Create a report
title: ''
labels: ''
assignees: ''
---
**Describe the issue**
A clear and concise description of what the issue is.
**To Reproduce**
- OS
- Compiler, compiler version, compile options
- Please attach minimal and reproducible .glTF file if you got an issue related to .glTF data
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

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,33 +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 example" OFF) )
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" 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)
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
ADD_SUBDIRECTORY ( examples/build-gltf )
endif (TINYGLTF_BUILD_BUILDER_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,29 +2,21 @@
`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(but not maintained anymore).
## 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)!
### Branches
* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson)
## Builds ## Builds
[![Build Status](https://travis-ci.org/syoyo/tinygltf.svg?branch=devel)](https://travis-ci.org/syoyo/tinygltf) [![Build Status](https://travis-ci.org/syoyo/tinygltf.svg?branch=devel)](https://travis-ci.org/syoyo/tinygltf)
[![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.
@@ -40,11 +32,9 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch(bu
* 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.
@@ -64,20 +54,12 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch(bu
* [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
* [glview](examples/glview) : Simple glTF geometry viewer. * [glview](examples/glview) : Simple glTF geometry viewer.
* [validator](examples/validator) : Simple glTF validator with JSON schema. * [validator](examples/validator) : Simple glTF validator with JSON schema.
* [basic](examples/basic) : Basic glTF viewer with texturing support. * [basic](examples/basic) : Basic glTF viewer with texturing support.
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
## Projects using TinyGLTF ## Projects using TinyGLTF
@@ -85,15 +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
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and proessional development of its developer
* 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.
@@ -101,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
@@ -121,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
@@ -130,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"
@@ -142,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());
@@ -157,12 +142,9 @@ if (!ret) {
} }
``` ```
#### Loader options
* `TinyGLTF::SetPreserveimageChannels(bool onoff)`. `true` to preserve image channels as stored in image file for loaded image. `false` by default for backward compatibility(image channels are widen to `RGBA` 4 channels). Effective only when using builtin image loader(STB image loader).
## 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.
@@ -172,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.
@@ -215,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

@@ -1,6 +1,5 @@
.vs .vs
Debug Debug
Release
x64 x64
packages packages

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

@@ -22,32 +22,32 @@
<VCProjectVersion>15.0</VCProjectVersion> <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid> <ProjectGuid>{0589AC44-0CF3-40D8-8D89-68393CFD40F3}</ProjectGuid>
<RootNamespace>basic</RootNamespace> <RootNamespace>basic</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset> <PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@@ -1,381 +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;
// Note (PE): On laptops with intel hd graphics card you can overcome the segfault by enabling experimental, see below (tested on lenovo thinkpad) #endif
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glewInit();
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
glewExperimental = GL_TRUE; << std::endl;
#ifdef __APPLE__ if (!GLEW_VERSION_3_3) {
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
#endif return EXIT_FAILURE;
}
Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glewExperimental = GL_TRUE; glEnable(GL_BLEND);
#endif
displayLoop(window, filename);
glewInit();
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION) glfwTerminate();
<< std::endl; return 0;
}
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}

View File

@@ -1,2 +0,0 @@
all:
$(CXX) -o create_triangle_gltf -I../../ create_triangle_gltf.cpp

View File

@@ -1,121 +0,0 @@
// An example of how to generate a gltf file from scratch. This example
// was translated from the pygltlib documentation in the pypi project page,
// which in turn is based on the Khronos Sample Models at:
//
// https://github.com/KhronosGroup/glTF-Sample-Models
//
// This example is released under the MIT license.
//
// 2021-02-25 Thu
// Dov Grobgeld <dov.grobgeld@gmail.com>
// Define these only in *one* .cc file.
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
#include "tiny_gltf.h"
int main(int argc, char **argv)
{
// Create a model with a single mesh and save it as a gltf file
tinygltf::Model m;
tinygltf::Scene scene;
tinygltf::Mesh mesh;
tinygltf::Primitive primitive;
tinygltf::Node node;
tinygltf::Buffer buffer;
tinygltf::BufferView bufferView1;
tinygltf::BufferView bufferView2;
tinygltf::Accessor accessor1;
tinygltf::Accessor accessor2;
tinygltf::Asset asset;
// This is the raw data buffer.
buffer.data = {
// 6 bytes of indices and two bytes of padding
0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,
// 36 bytes of floating point numbers
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
0x00,0x00,0x00,0x00};
// "The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
// start of the buffer.
bufferView1.buffer = 0;
bufferView1.byteOffset=0;
bufferView1.byteLength=6;
bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
// at position 8 in the buffer and are of type ARRAY_BUFFER
bufferView2.buffer = 0;
bufferView2.byteOffset=8;
bufferView2.byteLength=36;
bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
// Describe the layout of bufferView1, the indices of the vertices
accessor1.bufferView = 0;
accessor1.byteOffset = 0;
accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
accessor1.count = 3;
accessor1.type = TINYGLTF_TYPE_SCALAR;
accessor1.maxValues.push_back(2);
accessor1.minValues.push_back(0);
// Describe the layout of bufferView2, the vertices themself
accessor2.bufferView = 1;
accessor2.byteOffset = 0;
accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
accessor2.count = 3;
accessor2.type = TINYGLTF_TYPE_VEC3;
accessor2.maxValues = {1.0, 1.0, 0.0};
accessor2.minValues = {0.0, 0.0, 0.0};
// Build the mesh primitive and add it to the mesh
primitive.indices = 0; // The index of the accessor for the vertex indices
primitive.attributes["POSITION"] = 1; // The index of the accessor for positions
primitive.material = 0;
primitive.mode = TINYGLTF_MODE_TRIANGLES;
mesh.primitives.push_back(primitive);
// Other tie ups
node.mesh = 0;
scene.nodes.push_back(0); // Default scene
// Define the asset. The version is required
asset.version = "2.0";
asset.generator = "tinygltf";
// Now all that remains is to tie back all the loose objects into the
// our single model.
m.scenes.push_back(scene);
m.meshes.push_back(mesh);
m.nodes.push_back(node);
m.buffers.push_back(buffer);
m.bufferViews.push_back(bufferView1);
m.bufferViews.push_back(bufferView2);
m.accessors.push_back(accessor1);
m.accessors.push_back(accessor2);
m.asset = asset;
// Create a simple material
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
mat.doubleSided = true;
m.materials.push_back(mat);
// Save it to a file
tinygltf::TinyGLTF gltf;
gltf.WriteGltfSceneToFile(&m, "triangle.gltf",
true, // embedImages
true, // embedBuffers
true, // pretty print
false); // write binary
exit(0);
}

View File

@@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(dxview)
find_package(glfw3 CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
add_executable(dxview
src/Viewer.h
src/Viewer.cc
src/dxview.cc
)
target_include_directories(dxview
PRIVATE
../../
)
target_compile_definitions(dxview
PRIVATE
DXVIEW_SWAP_CHAIN_BUFFER_COUNT=3
DXVIEW_RES_DIR=L"${PROJECT_SOURCE_DIR}/res"
)
target_link_libraries(dxview
PRIVATE
dxgi
d3dcompiler
d3d12
glfw
spdlog::spdlog
)
set_target_properties(dxview
PROPERTIES
CXX_STANDARD 17
)

View File

@@ -1,37 +0,0 @@
# DirectX glTF Viewer
## Overview
This project was motivated by a lack of sample code demonstrating the graphics API agnostic nature of the glTF specification. The sample code is written using modern C++ and DirectX 12 for the client application.
## Features
* [x] DirectX 12
* [ ] Loader
* [ ] Animation
* [ ] Morph Target
* [ ] Physical Base Rendering
* [ ] Environment Map
## Dependencies
* [CMake](https://github.com/Kitware/CMake)
* [Vcpkg](https://github.com/Microsoft/vcpkg)
* [GLFW](https://github.com/glfw/glfw)
* [spdlog](https://github.com/gabime/spdlog)
## Building
### Install dependencies
```
vcpkg install glfw3:x64-windows
vcpkg install spdlog:x64-windows
```
### Generate Project Files
```
mkdir build
cmake . -B build -DCMAKE_TOOLCHAIN_FILE=${VCPKG_DIR}/script/buildsystem/vcpkg.cmake
```

View File

@@ -1,3 +0,0 @@
float4 main() : SV_Target {
return float4(0.5, 0.5, 0.5, 1.0);
}

View File

@@ -1,52 +0,0 @@
struct RS2PS {
float4 position : SV_POSITION;
#ifdef HAS_TEXCOORD_0
float2 texcoord_0: TEXCOORD_0;
#endif
};
struct TextureInfo {
uint textureIndex;
uint samplerIndex;
};
struct PBRMetallicRoughness {
float4 baseColorFactor;
TextureInfo baseColorTexture;
float metallicFactor;
float roughnessFactor;
TextureInfo metallicRoughnessTexture;
};
cbuffer Material : register(b2) {
PBRMetallicRoughness pbrMetallicRoughness;
};
Texture2D textures[5] : register(t0);
SamplerState samplerState[5] : register(s0);
float4 getBaseColor(float2 uv) {
float4 baseColor = pbrMetallicRoughness.baseColorFactor;
#ifdef HAS_TEXCOORD_0
TextureInfo baseColorTexture = pbrMetallicRoughness.baseColorTexture;
if (baseColorTexture.textureIndex >= 0) {
baseColor *= textures[baseColorTexture.textureIndex].Sample(samplerState[baseColorTexture.samplerIndex], uv);
}
#endif
return baseColor;
}
float4 main(RS2PS input) : SV_Target {
float2 uv = float2(0.0, 0.0);
#ifdef HAS_TEXCOORD_0
uv = input.texcoord_0;
#endif
float4 color = getBaseColor(uv);
return color;
}

View File

@@ -1,46 +0,0 @@
struct IA2VS {
float3 position : POSITION;
#ifdef HAS_NORMAL
float3 normal : NORMAL;
#endif
#ifdef HAS_TANGENT
float4 tangent : TANGENT;
#endif
#ifdef HAS_TEXCOORD_0
float2 texcoord_0: TEXCOORD_0;
#endif
};
struct VS2RS {
float4 position : SV_POSITION;
#ifdef HAS_TEXCOORD_0
float2 texcoord_0: TEXCOORD_0;
#endif
};
cbuffer Camera : register(b0) {
float4x4 V;
float4x4 P;
float4x4 VP;
};
cbuffer Node : register(b1) {
float4x4 M;
};
VS2RS main(IA2VS input) {
VS2RS output;
output.position = mul(float4(input.position, 1.0), M);
output.position = mul(output.position, V);
output.position = mul(output.position, P);
#ifdef HAS_TEXCOORD_0
output.texcoord_0 = input.texcoord_0;
#endif
return output;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +0,0 @@
#ifndef DXVIEW_VIEWER_GUARD
#define DXVIEW_VIEWER_GUARD
#include <DirectXMath.h>
#include <d3d12.h>
#include <dxgi1_6.h>
#include <tiny_gltf.h>
#include <wrl.h>
#include <filesystem>
#include <map>
#include <string>
#include <vector>
using Microsoft::WRL::ComPtr;
enum RenderPassType { RENDER_PASS_TYPE_PRESENT = 0, RENDER_PASS_TYPE_COUNT };
struct RenderTarget {
ComPtr<ID3D12Resource> pTexture;
D3D12_CPU_DESCRIPTOR_HANDLE viewDescriptor;
};
struct TextureInfo {
int32_t textureIndex;
int32_t samplerIndex;
};
struct PBRMetallicRoughness {
DirectX::XMFLOAT4 baseColorFactor;
TextureInfo baseColorTexture;
float metallicFactor;
float roughnessFactor;
TextureInfo metallicRoughnessTexture;
};
struct Material {
std::string name;
D3D12_BLEND_DESC blendDesc;
D3D12_RASTERIZER_DESC rasterizerDesc;
ComPtr<ID3D12Resource> pBuffer;
void* pBufferData;
ComPtr<ID3D12DescriptorHeap> pSRVDescriptorHeap;
ComPtr<ID3D12DescriptorHeap> pSamplerDescriptorHeap;
};
struct Attribute {
std::string name;
DXGI_FORMAT format;
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
};
struct Primitive {
std::vector<Attribute> attributes;
uint32_t vertexCount;
D3D12_PRIMITIVE_TOPOLOGY primitiveTopology;
D3D12_INDEX_BUFFER_VIEW indexBufferView;
uint32_t indexCount;
Material* pMaterial;
ComPtr<ID3D12RootSignature> pRootSignature;
ComPtr<ID3D12PipelineState> pPipelineState;
};
struct Mesh {
std::string name;
std::vector<Primitive> primitives;
};
struct Node {
DirectX::XMFLOAT4X4 M;
};
struct Camera {
DirectX::XMFLOAT4X4 V;
DirectX::XMFLOAT4X4 P;
DirectX::XMFLOAT4X4 VP;
};
class Viewer {
public:
Viewer(HWND window, tinygltf::Model* pModel);
void update(double deltaTime);
void render(double deltaTime);
private:
void initDirectX(HWND window);
void buildRenderTargets();
void buildResources();
void buildBuffers(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
void buildImages(std::vector<ComPtr<ID3D12Resource> >* pStagingResources);
void buildSamplerDescs();
void buildMaterials();
void buildMeshes();
void buildNodes();
void drawNode(uint64_t nodeIndex);
private:
tinygltf::Model* pModel_;
ComPtr<IDXGIFactory1> pFactory_;
ComPtr<IDXGIAdapter1> pAdapter_;
ComPtr<ID3D12Device> pDevice_;
ComPtr<ID3D12CommandQueue> pDirectCommandQueue_;
UINT64 directFenceValue_;
ComPtr<ID3D12Fence> pDirectFence_;
ComPtr<ID3D12CommandQueue> pCopyCommandQueue_;
UINT64 copyFenceValue_;
ComPtr<ID3D12Fence> pCopyFence_;
ComPtr<IDXGISwapChain3> pSwapChain_;
ComPtr<ID3D12Resource> pSwapChainBuffers_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
ComPtr<ID3D12CommandAllocator>
pDirectCommandAllocators_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
ComPtr<ID3D12GraphicsCommandList> pDirectCommandList_;
ComPtr<ID3D12CommandAllocator> pCopyCommandAllocator_;
ComPtr<ID3D12GraphicsCommandList> pCopyCommandList_;
UINT descriptorIncrementSize_[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
ComPtr<ID3D12DescriptorHeap>
pRTVDescriptorHeaps_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
std::vector<RenderTarget> renderTargets_[DXVIEW_SWAP_CHAIN_BUFFER_COUNT];
std::vector<ComPtr<ID3D12Resource> > pBuffers_;
std::vector<ComPtr<ID3D12Resource> > pTextures_;
std::vector<D3D12_SAMPLER_DESC> samplerDescs_;
std::vector<Material> materials_;
std::vector<Mesh> meshes_;
std::vector<ComPtr<ID3D12Resource> > pNodeBuffers_;
ComPtr<ID3D12Resource> pCameraBuffer_;
};
#endif

View File

@@ -1,90 +0,0 @@
#define GLFW_EXPOSE_NATIVE_WIN32
#define TINYGLTF_IMPLEMENTATION
#define STBI_MSC_SECURE_CRT
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <spdlog/spdlog.h>
#include <tiny_gltf.h>
#undef GLFW_EXPOSE_NATIVE_WIN32
#undef TINYGLTF_IMPLEMENTATION
#undef STBI_MSC_SECURE_CRT
#undef STB_IMAGE_IMPLEMENTATION
#undef STB_IMAGE_WRITE_IMPLEMENTATION
#include <iostream>
#include <string>
#include "Viewer.h"
static void onError(int error, const char* message) {
spdlog::error("[{}] {}", error, message);
}
static void onRender(Viewer* pViewer, double deltaTime) {
pViewer->update(deltaTime);
pViewer->render(deltaTime);
}
int main(int argc, char* argv[]) {
tinygltf::TinyGLTF context;
tinygltf::Model model;
std::string error;
std::string warning;
if (!context.LoadASCIIFromFile(&model, &error, &warning, argv[1])) {
if (!error.empty()) {
spdlog::error("{}", error);
}
if (!warning.empty()) {
spdlog::warn("{}", warning);
}
exit(EXIT_FAILURE);
}
GLFWwindow* pWindow;
glfwSetErrorCallback(onError);
if (!glfwInit()) {
spdlog::error("Fail to initialize GLFW!!!");
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
pWindow = glfwCreateWindow(512, 512, "dxview", nullptr, nullptr);
if (!pWindow) {
spdlog::error("Fail to create GLFWwindow!!!");
glfwTerminate();
exit(EXIT_FAILURE);
}
auto pViewer = std::make_unique<Viewer>(glfwGetWin32Window(pWindow), &model);
if (!pViewer) {
spdlog::error("Fail to create Viewer");
glfwDestroyWindow(pWindow);
glfwTerminate();
exit(EXIT_FAILURE);
}
auto prevTimeStamp = glfwGetTime();
while (!glfwWindowShouldClose(pWindow)) {
auto currTimeStamp = glfwGetTime();
onRender(pViewer.get(), currTimeStamp - prevTimeStamp);
prevTimeStamp = currTimeStamp;
glfwPollEvents();
}
glfwDestroyWindow(pWindow);
glfwTerminate();
exit(EXIT_SUCCESS);
}

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

@@ -3,9 +3,6 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h" #include "tiny_gltf.h"
// Nlohmann json(include ../json.hpp)
#include "json.hpp"
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp" #include "catch.hpp"
@@ -16,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;
@@ -31,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);
@@ -48,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);
} }
@@ -93,362 +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);
}
TEST_CASE("serialize-empty-material", "[issue-294]") {
tinygltf::Model m;
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 1.0f, 1.0f, 1.0f}; // default baseColorFactor
m.materials.push_back(mat);
std::stringstream os;
tinygltf::TinyGLTF ctx;
ctx.WriteGltfSceneToStream(&m, os, false, false);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(1 == j["materials"].size());
REQUIRE(j["materials"][0].is_object());
}
#ifndef TINYGLTF_NO_FS
TEST_CASE("expandpath-utf-8", "[pr-226]") {
std::string s1 = "\xe5\xaf\xb9"; // utf-8 string
std::string ret = tinygltf::ExpandFilePath(s1, /* userdata */nullptr);
// expected: E5 AF B9
REQUIRE(3 == ret.size());
REQUIRE(0xe5 == static_cast<uint8_t>(ret[0]));
REQUIRE(0xaf == static_cast<uint8_t>(ret[1]));
REQUIRE(0xb9 == static_cast<uint8_t>(ret[2]));
}
#endif

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