mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 18:58:53 +00:00
Compare commits
85 Commits
uri-decode
...
empty-mate
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1923067982 | ||
|
|
68adc4ba5e | ||
|
|
42a8cd50ff | ||
|
|
0543640a83 | ||
|
|
9c59a0b64c | ||
|
|
452541a231 | ||
|
|
78fe8d9b89 | ||
|
|
51e5508fa0 | ||
|
|
91da299729 | ||
|
|
50ae8a31a8 | ||
|
|
0af0435ef1 | ||
|
|
7c342533e9 | ||
|
|
7842c1276f | ||
|
|
125e4a2033 | ||
|
|
c9d6c5b9b4 | ||
|
|
96a8b2c69b | ||
|
|
01d54380ac | ||
|
|
6cd8fdb2c8 | ||
|
|
fe01af2f01 | ||
|
|
efdd2b04dc | ||
|
|
2e642b3322 | ||
|
|
1739d025a9 | ||
|
|
39418e5728 | ||
|
|
5622d2762d | ||
|
|
3d939fd3ee | ||
|
|
fbbeb4d6a9 | ||
|
|
cef1787ef8 | ||
|
|
2f5aa9f13b | ||
|
|
28bafe4b11 | ||
|
|
34894a6325 | ||
|
|
2e7006797b | ||
|
|
d9c03d041a | ||
|
|
50a3061ddf | ||
|
|
014dce27f4 | ||
|
|
c046769054 | ||
|
|
c43266fdc9 | ||
|
|
aca196e8d3 | ||
|
|
b48c027c9a | ||
|
|
db5c3bea45 | ||
|
|
ddfa1f2f0b | ||
|
|
7b69c778fe | ||
|
|
73e73bf3c1 | ||
|
|
35d664e417 | ||
|
|
272a9dfa5f | ||
|
|
f3bf6ee78e | ||
|
|
aba57bb907 | ||
|
|
6fad7adb9c | ||
|
|
3dad303bea | ||
|
|
ff0a2e9fb4 | ||
|
|
fe77cc5cdd | ||
|
|
18f0e20a11 | ||
|
|
978adee547 | ||
|
|
73c4cce303 | ||
|
|
925b83627a | ||
|
|
92c23725ae | ||
|
|
af750a5104 | ||
|
|
ff48fa0ff4 | ||
|
|
ec45334d3d | ||
|
|
5f603c56dc | ||
|
|
063b8586f1 | ||
|
|
db855c6794 | ||
|
|
e391f6b03e | ||
|
|
5ecede71f0 | ||
|
|
40982716f9 | ||
|
|
4bdc96fb9b | ||
|
|
96ecea080a | ||
|
|
22bfc843ee | ||
|
|
eaa25a307a | ||
|
|
ab600b8e72 | ||
|
|
eb9d29c06e | ||
|
|
57356933c5 | ||
|
|
c3d6716c56 | ||
|
|
ac5e09f8c3 | ||
|
|
e2c3fe1c0b | ||
|
|
973d9b3394 | ||
|
|
28ad4ab7b8 | ||
|
|
0227ae5d9b | ||
|
|
a0a62bde1c | ||
|
|
23d1ff2880 | ||
|
|
bcf2ce586e | ||
|
|
aa3c5a1cad | ||
|
|
1cf179d377 | ||
|
|
ddc14f8ba6 | ||
|
|
379bb612f1 | ||
|
|
1da4e5d633 |
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
30
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
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.
|
||||||
165
.github/workflows/c-cpp.yml
vendored
Normal file
165
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
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
|
||||||
|
|
||||||
@@ -4,18 +4,24 @@ PROJECT (tinygltf)
|
|||||||
|
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
option(TINYGLTF_BUILD_EXAMPLES "Build examples" ON)
|
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example" ON)
|
||||||
|
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
||||||
|
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_EXAMPLES)
|
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||||
ADD_EXECUTABLE ( loader_example
|
ADD_EXECUTABLE ( loader_example
|
||||||
loader_example.cc
|
loader_example.cc
|
||||||
)
|
)
|
||||||
|
endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||||
|
|
||||||
|
if (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||||
ADD_SUBDIRECTORY ( examples/gltfutil )
|
ADD_SUBDIRECTORY ( examples/gltfutil )
|
||||||
ADD_SUBDIRECTORY ( examples/glview )
|
ADD_SUBDIRECTORY ( examples/glview )
|
||||||
ADD_SUBDIRECTORY ( examples/validator )
|
endif (TINYGLTF_BUILD_GL_EXAMPLES)
|
||||||
endif (TINYGLTF_BUILD_EXAMPLES)
|
|
||||||
|
|
||||||
|
if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||||
|
ADD_SUBDIRECTORY ( examples/validator )
|
||||||
|
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
|
||||||
#
|
#
|
||||||
# TinuGLTF is a header-only library, so no library build. just install header files.
|
# TinuGLTF is a header-only library, so no library build. just install header files.
|
||||||
#
|
#
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -3,7 +3,7 @@
|
|||||||
`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 Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler.
|
||||||
If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
If you are looking for old, C++03 version, please use `devel-picojson` branch(but not maintained anymore).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -13,12 +13,18 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
|
|||||||
- 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
|
||||||
|
|
||||||
[](https://travis-ci.org/syoyo/tinygltf)
|
[](https://travis-ci.org/syoyo/tinygltf)
|
||||||
|
|
||||||
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
[](https://ci.appveyor.com/project/syoyo/tinygltf)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Written in portable C++. C++-11 with STL dependency only.
|
* Written in portable C++. C++-11 with STL dependency only.
|
||||||
@@ -83,6 +89,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
|||||||
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
|
* [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
|
* [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.
|
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
|
||||||
|
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
|
||||||
* Your projects here! (Please send PR)
|
* Your projects here! (Please send PR)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
@@ -202,6 +209,13 @@ $ ./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>.
|
||||||
|
|||||||
1
examples/basic/.gitignore
vendored
1
examples/basic/.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.vs
|
.vs
|
||||||
Debug
|
Debug
|
||||||
|
Release
|
||||||
x64
|
x64
|
||||||
packages
|
packages
|
||||||
|
|
||||||
|
|||||||
@@ -19,3 +19,7 @@ $ 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).
|
||||||
|
|
||||||
|
|||||||
@@ -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.17134.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.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>v141</PlatformToolset>
|
<PlatformToolset>v142</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>v141</PlatformToolset>
|
<PlatformToolset>v142</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>v141</PlatformToolset>
|
<PlatformToolset>v142</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>v141</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -100,42 +100,49 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
|||||||
std::cout << "vaa missing: " << attrib.first << std::endl;
|
std::cout << "vaa missing: " << attrib.first << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint texid;
|
if (model.textures.size() > 0) {
|
||||||
glGenTextures(1, &texid);
|
// fixme: Use material's baseColor
|
||||||
|
tinygltf::Texture &tex = model.textures[0];
|
||||||
|
|
||||||
tinygltf::Texture &tex = model.textures[0];
|
if (tex.source > -1) {
|
||||||
tinygltf::Image &image = model.images[tex.source];
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texid);
|
GLuint texid;
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glGenTextures(1, &texid);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
||||||
|
|
||||||
GLenum format = GL_RGBA;
|
tinygltf::Image &image = model.images[tex.source];
|
||||||
|
|
||||||
if (image.component == 1) {
|
glBindTexture(GL_TEXTURE_2D, texid);
|
||||||
format = GL_RED;
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
} else if (image.component == 2) {
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
format = GL_RG;
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
} else if (image.component == 3) {
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
format = GL_RGB;
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
} else {
|
|
||||||
// ???
|
GLenum format = GL_RGBA;
|
||||||
|
|
||||||
|
if (image.component == 1) {
|
||||||
|
format = GL_RED;
|
||||||
|
} else if (image.component == 2) {
|
||||||
|
format = GL_RG;
|
||||||
|
} else if (image.component == 3) {
|
||||||
|
format = GL_RGB;
|
||||||
|
} else {
|
||||||
|
// ???
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum type = GL_UNSIGNED_BYTE;
|
||||||
|
if (image.bits == 8) {
|
||||||
|
// ok
|
||||||
|
} else if (image.bits == 16) {
|
||||||
|
type = GL_UNSIGNED_SHORT;
|
||||||
|
} else {
|
||||||
|
// ???
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
||||||
|
format, type, &image.image.at(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum type = GL_UNSIGNED_BYTE;
|
|
||||||
if (image.bits == 8) {
|
|
||||||
// ok
|
|
||||||
} else if (image.bits == 16) {
|
|
||||||
type = GL_UNSIGNED_SHORT;
|
|
||||||
} else {
|
|
||||||
// ???
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
|
|
||||||
format, type, &image.image.at(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vbos;
|
return vbos;
|
||||||
@@ -144,8 +151,12 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
|||||||
// bind models
|
// bind models
|
||||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
||||||
tinygltf::Node &node) {
|
tinygltf::Node &node) {
|
||||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||||
|
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
|
assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size()));
|
||||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,6 +168,7 @@ GLuint bindModel(tinygltf::Model &model) {
|
|||||||
|
|
||||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||||
|
assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
|
||||||
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +194,9 @@ void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
|||||||
|
|
||||||
// recursively draw node and children nodes of model
|
// recursively draw node and children nodes of model
|
||||||
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
|
||||||
drawMesh(model, model.meshes[node.mesh]);
|
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||||
|
drawMesh(model, model.meshes[node.mesh]);
|
||||||
|
}
|
||||||
for (size_t i = 0; i < node.children.size(); i++) {
|
for (size_t i = 0; i < node.children.size(); i++) {
|
||||||
drawModelNodes(model, model.nodes[node.children[i]]);
|
drawModelNodes(model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
@@ -315,7 +329,7 @@ static void error_callback(int error, const char *description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
std::string filename = "../../models/Cube/Cube.gltf";
|
std::string filename = "../../../models/Cube/Cube.gltf";
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
filename = argv[1];
|
filename = argv[1];
|
||||||
@@ -327,9 +341,12 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Force create OpenGL 3.3
|
// Force create OpenGL 3.3
|
||||||
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
|
||||||
|
// Note (PE): On laptops with intel hd graphics card you can overcome the segfault by enabling experimental, see below (tested on lenovo thinkpad)
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
glewExperimental = GL_TRUE;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
36
examples/dxview/CMakeLists.txt
Normal file
36
examples/dxview/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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
|
||||||
|
)
|
||||||
37
examples/dxview/README.md
Normal file
37
examples/dxview/README.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# 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
|
||||||
|
```
|
||||||
3
examples/dxview/res/gray.hlsl
Normal file
3
examples/dxview/res/gray.hlsl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
float4 main() : SV_Target {
|
||||||
|
return float4(0.5, 0.5, 0.5, 1.0);
|
||||||
|
}
|
||||||
52
examples/dxview/res/lighting.hlsl
Normal file
52
examples/dxview/res/lighting.hlsl
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
46
examples/dxview/res/primitive.hlsl
Normal file
46
examples/dxview/res/primitive.hlsl
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
1292
examples/dxview/src/Viewer.cc
Normal file
1292
examples/dxview/src/Viewer.cc
Normal file
File diff suppressed because it is too large
Load Diff
130
examples/dxview/src/Viewer.h
Normal file
130
examples/dxview/src/Viewer.h
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#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
|
||||||
90
examples/dxview/src/dxview.cc
Normal file
90
examples/dxview/src/dxview.cc
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
#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);
|
||||||
|
}
|
||||||
BIN
models/CubeImageUriSpaces/ 2x2 image has multiple spaces.png
Normal file
BIN
models/CubeImageUriSpaces/ 2x2 image has multiple spaces.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 B |
BIN
models/CubeImageUriSpaces/2x2 image has spaces.png
Normal file
BIN
models/CubeImageUriSpaces/2x2 image has spaces.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 79 B |
171
models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf
Normal file
171
models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 2,
|
||||||
|
"POSITION": 1,
|
||||||
|
"TEXCOORD_0": 3
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorTexture": {
|
||||||
|
"index": 0,
|
||||||
|
"texCoord": 0
|
||||||
|
},
|
||||||
|
"baseColorFactor": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor": 1,
|
||||||
|
"roughnessFactor": 1
|
||||||
|
},
|
||||||
|
"emissiveFactor": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"alphaMode": "OPAQUE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"sampler": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"wrapS": 33071,
|
||||||
|
"wrapT": 33071
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"uri": " 2x2 image has multiple spaces.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5121,
|
||||||
|
"count": 36,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.5,
|
||||||
|
-0.5,
|
||||||
|
-0.5
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 3,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 36,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 324,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 612,
|
||||||
|
"byteLength": 192
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 804,
|
||||||
|
"uri": "CubeImageUriSpaces.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
models/CubeImageUriSpaces/CubeImageUriSpaces.bin
Normal file
BIN
models/CubeImageUriSpaces/CubeImageUriSpaces.bin
Normal file
Binary file not shown.
171
models/CubeImageUriSpaces/CubeImageUriSpaces.gltf
Normal file
171
models/CubeImageUriSpaces/CubeImageUriSpaces.gltf
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 2,
|
||||||
|
"POSITION": 1,
|
||||||
|
"TEXCOORD_0": 3
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorTexture": {
|
||||||
|
"index": 0,
|
||||||
|
"texCoord": 0
|
||||||
|
},
|
||||||
|
"baseColorFactor": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor": 1,
|
||||||
|
"roughnessFactor": 1
|
||||||
|
},
|
||||||
|
"emissiveFactor": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"alphaMode": "OPAQUE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"source": 0,
|
||||||
|
"sampler": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers": [
|
||||||
|
{
|
||||||
|
"wrapS": 33071,
|
||||||
|
"wrapT": 33071
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"uri": "2x2 image has spaces.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5121,
|
||||||
|
"count": 36,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
0.5,
|
||||||
|
0.5,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.5,
|
||||||
|
-0.5,
|
||||||
|
-0.5
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 3,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 24,
|
||||||
|
"normalized": false,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 36,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 324,
|
||||||
|
"byteLength": 288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 612,
|
||||||
|
"byteLength": 192
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 804,
|
||||||
|
"uri": "CubeImageUriSpaces.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
models/Extensions-overwrite-issue261/issue-261.bin
Normal file
BIN
models/Extensions-overwrite-issue261/issue-261.bin
Normal file
Binary file not shown.
376
models/Extensions-overwrite-issue261/issue-261.gltf
Normal file
376
models/Extensions-overwrite-issue261/issue-261.gltf
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
46
tests/fuzzer/README.md
Normal file
46
tests/fuzzer/README.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Fuzzing test
|
||||||
|
|
||||||
|
Do fuzzing test for TinyGLTF API.
|
||||||
|
|
||||||
|
## Supported API
|
||||||
|
|
||||||
|
* [x] LoadASCIIFromMemory
|
||||||
|
* [ ] LoadBinaryFromMemory
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* meson
|
||||||
|
* clang with fuzzer support(`-fsanitize=fuzzer`. at least clang 8.0 should work)
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
### Ubuntu 18.04
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt install clang++-8
|
||||||
|
$ sudo apt install libfuzzer-8-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, if you didn't set `update-alternatives` you can set `clang++` to point to `clang++8`
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-8 10
|
||||||
|
$ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 10
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to compile
|
||||||
|
|
||||||
|
```
|
||||||
|
$ CXX=clang++ CC=clang meson build
|
||||||
|
$ cd build
|
||||||
|
$ ninja
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
Increase memory limit. e.g. `-rss_limit_mb=50000`
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./fuzz_gltf -rss_limit_mb=20000 -jobs 4
|
||||||
|
```
|
||||||
|
|
||||||
33
tests/fuzzer/fuzz_gltf.cc
Normal file
33
tests/fuzzer/fuzz_gltf.cc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
|
static void parse_intCoding4(const uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
const char *str = reinterpret_cast<const char *>(data);
|
||||||
|
|
||||||
|
bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, str, size, /* base_dir */"" );
|
||||||
|
(void)ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
int LLVMFuzzerTestOneInput(std::uint8_t const* data, std::size_t size)
|
||||||
|
{
|
||||||
|
parse_intCoding4(data, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
9
tests/fuzzer/meson.build
Normal file
9
tests/fuzzer/meson.build
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
project('fuzz_tinygltf', 'cpp', default_options : ['cpp_std=c++11'])
|
||||||
|
|
||||||
|
incdirs = include_directories('../../')
|
||||||
|
executable('fuzz_gltf',
|
||||||
|
'fuzz_gltf.cc',
|
||||||
|
include_directories : incdirs,
|
||||||
|
cpp_args : '-fsanitize=address,fuzzer',
|
||||||
|
link_args : '-fsanitize=address,fuzzer' )
|
||||||
|
|
||||||
120
tests/tester.cc
120
tests/tester.cc
@@ -3,6 +3,9 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@@ -93,6 +96,59 @@ TEST_CASE("extension-with-empty-object", "[issue-97]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]") {
|
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
|
||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
tinygltf::TinyGLTF ctx;
|
tinygltf::TinyGLTF ctx;
|
||||||
@@ -333,3 +389,67 @@ TEST_CASE("pbr-khr-texture-transform", "[material]") {
|
|||||||
REQUIRE(scale[1] == 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["asset"].is_null());
|
||||||
|
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
|
||||||
|
|||||||
320
tiny_gltf.h
320
tiny_gltf.h
@@ -4,7 +4,7 @@
|
|||||||
//
|
//
|
||||||
// The MIT License (MIT)
|
// The MIT License (MIT)
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015 - 2019 Syoyo Fujita, Aurélien Chatelain and many
|
// Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many
|
||||||
// contributors.
|
// contributors.
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
// Version:
|
// Version:
|
||||||
|
// - v2.4.3 Fix null object output when when material has all default parameters.
|
||||||
// - v2.4.2 Decode percent-encoded URI.
|
// - v2.4.2 Decode percent-encoded URI.
|
||||||
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
|
||||||
// `extras` property.
|
// `extras` property.
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath> // std::fabs
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -322,7 +324,8 @@ class Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use this function if you want to have number value as int.
|
// Use this function if you want to have number value as int.
|
||||||
double GetNumberAsInt() const {
|
// TODO(syoyo): Support int value larger than 32 bits
|
||||||
|
int GetNumberAsInt() const {
|
||||||
if (type_ == REAL_TYPE) {
|
if (type_ == REAL_TYPE) {
|
||||||
return int(real_value_);
|
return int(real_value_);
|
||||||
} else {
|
} else {
|
||||||
@@ -527,10 +530,12 @@ struct AnimationChannel {
|
|||||||
// "weights"]
|
// "weights"]
|
||||||
Value extras;
|
Value extras;
|
||||||
ExtensionMap extensions;
|
ExtensionMap extensions;
|
||||||
|
ExtensionMap target_extensions;
|
||||||
|
|
||||||
// Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
|
// Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
|
||||||
std::string extras_json_string;
|
std::string extras_json_string;
|
||||||
std::string extensions_json_string;
|
std::string extensions_json_string;
|
||||||
|
std::string target_extensions_json_string;
|
||||||
|
|
||||||
AnimationChannel() : sampler(-1), target_node(-1) {}
|
AnimationChannel() : sampler(-1), target_node(-1) {}
|
||||||
DEFAULT_METHODS(AnimationChannel)
|
DEFAULT_METHODS(AnimationChannel)
|
||||||
@@ -660,6 +665,8 @@ struct Image {
|
|||||||
width = -1;
|
width = -1;
|
||||||
height = -1;
|
height = -1;
|
||||||
component = -1;
|
component = -1;
|
||||||
|
bits = -1;
|
||||||
|
pixel_type = -1;
|
||||||
}
|
}
|
||||||
DEFAULT_METHODS(Image)
|
DEFAULT_METHODS(Image)
|
||||||
|
|
||||||
@@ -992,6 +999,7 @@ struct Primitive {
|
|||||||
Primitive() {
|
Primitive() {
|
||||||
material = -1;
|
material = -1;
|
||||||
indices = -1;
|
indices = -1;
|
||||||
|
mode = -1;
|
||||||
}
|
}
|
||||||
DEFAULT_METHODS(Primitive)
|
DEFAULT_METHODS(Primitive)
|
||||||
bool operator==(const Primitive &) const;
|
bool operator==(const Primitive &) const;
|
||||||
@@ -1111,9 +1119,9 @@ struct SpotLight {
|
|||||||
struct Light {
|
struct Light {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<double> color;
|
std::vector<double> color;
|
||||||
double intensity;
|
double intensity{1.0};
|
||||||
std::string type;
|
std::string type;
|
||||||
double range;
|
double range{0.0}; // 0.0 = inifinite
|
||||||
SpotLight spot;
|
SpotLight spot;
|
||||||
|
|
||||||
Light() : intensity(1.0), range(0.0) {}
|
Light() : intensity(1.0), range(0.0) {}
|
||||||
@@ -1151,7 +1159,7 @@ class Model {
|
|||||||
std::vector<Scene> scenes;
|
std::vector<Scene> scenes;
|
||||||
std::vector<Light> lights;
|
std::vector<Light> lights;
|
||||||
|
|
||||||
int defaultScene;
|
int defaultScene = -1;
|
||||||
std::vector<std::string> extensionsUsed;
|
std::vector<std::string> extensionsUsed;
|
||||||
std::vector<std::string> extensionsRequired;
|
std::vector<std::string> extensionsRequired;
|
||||||
|
|
||||||
@@ -1245,7 +1253,14 @@ struct FsCallbacks {
|
|||||||
|
|
||||||
bool FileExists(const std::string &abs_filename, void *);
|
bool FileExists(const std::string &abs_filename, void *);
|
||||||
|
|
||||||
std::string ExpandFilePath(const std::string &filepath, void *);
|
///
|
||||||
|
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to
|
||||||
|
/// `C:\Users\tinygltf\AppData`)
|
||||||
|
///
|
||||||
|
/// @param[in] filepath File path string. Assume UTF-8
|
||||||
|
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
|
||||||
|
///
|
||||||
|
std::string ExpandFilePath(const std::string &filepath, void *userdata);
|
||||||
|
|
||||||
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
const std::string &filepath, void *);
|
const std::string &filepath, void *);
|
||||||
@@ -2144,12 +2159,12 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
namespace dlib {
|
namespace dlib {
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
inline unsigned char to_hex( unsigned char x )
|
inline unsigned char to_hex( unsigned char x )
|
||||||
{
|
{
|
||||||
return x + (x > 9 ? ('A'-10) : '0');
|
return x + (x > 9 ? ('A'-10) : '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string urlencode( const std::string& s )
|
const std::string urlencode( const std::string& s )
|
||||||
{
|
{
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
|
|
||||||
@@ -2479,6 +2494,15 @@ static inline std::wstring UTF8ToWchar(const std::string &str) {
|
|||||||
(int)wstr.size());
|
(int)wstr.size());
|
||||||
return wstr;
|
return wstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline std::string WcharToUTF8(const std::wstring &wstr) {
|
||||||
|
int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(),
|
||||||
|
nullptr, 0, NULL, NULL);
|
||||||
|
std::string str(str_size, 0);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
|
||||||
|
(int)str.size(), NULL, NULL);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_FS
|
#ifndef TINYGLTF_NO_FS
|
||||||
@@ -2530,15 +2554,16 @@ bool FileExists(const std::string &abs_filename, void *) {
|
|||||||
|
|
||||||
std::string ExpandFilePath(const std::string &filepath, void *) {
|
std::string ExpandFilePath(const std::string &filepath, void *) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
|
// Assume input `filepath` is encoded in UTF-8
|
||||||
char *str = new char[len];
|
std::wstring wfilepath = UTF8ToWchar(filepath);
|
||||||
ExpandEnvironmentStringsA(filepath.c_str(), str, len);
|
DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0);
|
||||||
|
wchar_t *wstr = new wchar_t[wlen];
|
||||||
|
ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen);
|
||||||
|
|
||||||
std::string s(str);
|
std::wstring ws(wstr);
|
||||||
|
delete[] wstr;
|
||||||
|
return WcharToUTF8(ws);
|
||||||
|
|
||||||
delete[] str;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
@@ -2553,8 +2578,10 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quote the string to keep any spaces in filepath intact.
|
||||||
|
std::string quoted_path = "\"" + filepath + "\"";
|
||||||
// char** w;
|
// char** w;
|
||||||
int ret = wordexp(filepath.c_str(), &p, 0);
|
int ret = wordexp(quoted_path.c_str(), &p, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// err
|
// err
|
||||||
s = filepath;
|
s = filepath;
|
||||||
@@ -2588,11 +2615,12 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t size = AAsset_getLength(asset);
|
size_t size = AAsset_getLength(asset);
|
||||||
if (size <= 0) {
|
if (size == 0) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Invalid file size : " + filepath +
|
(*err) += "Invalid file size : " + filepath +
|
||||||
" (does the path point to a directory?)";
|
" (does the path point to a directory?)";
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
out->resize(size);
|
out->resize(size);
|
||||||
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
|
||||||
@@ -2611,9 +2639,12 @@ bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
|||||||
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
||||||
std::istream f(&wfile_buf);
|
std::istream f(&wfile_buf);
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
|
||||||
|
// For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
|
||||||
|
// `wchar_t *`
|
||||||
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
|
||||||
#else // clang?
|
#else
|
||||||
|
// Unknown compiler/runtime
|
||||||
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
std::ifstream f(filepath.c_str(), std::ifstream::binary);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
@@ -2655,9 +2686,10 @@ bool WriteWholeFile(std::string *err, const std::string &filepath,
|
|||||||
const std::vector<unsigned char> &contents, void *) {
|
const std::vector<unsigned char> &contents, void *) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if defined(__GLIBCXX__) // mingw
|
#if defined(__GLIBCXX__) // mingw
|
||||||
int file_descriptor =
|
int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
|
||||||
_wopen(UTF8ToWchar(filepath).c_str(), _O_WRONLY | _O_BINARY);
|
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||||
|
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||||
std::ostream f(&wfile_buf);
|
std::ostream f(&wfile_buf);
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
|
||||||
@@ -2708,12 +2740,13 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|||||||
void *user_data = nullptr) {
|
void *user_data = nullptr) {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string ext;
|
std::string ext;
|
||||||
|
// If image has uri, use it it as a filename
|
||||||
// If image have uri. Use it it as a filename
|
|
||||||
if (image.uri.size()) {
|
if (image.uri.size()) {
|
||||||
filename = GetBaseFilename(image.uri);
|
filename = GetBaseFilename(image.uri);
|
||||||
ext = GetFilePathExtension(filename);
|
ext = GetFilePathExtension(filename);
|
||||||
|
} else if (image.bufferView != -1) {
|
||||||
|
// If there's no URI and the data exists in a buffer,
|
||||||
|
// don't change properties or write images
|
||||||
} else if (image.name.size()) {
|
} else if (image.name.size()) {
|
||||||
ext = MimeToExt(image.mimeType);
|
ext = MimeToExt(image.mimeType);
|
||||||
// Otherwise use name as filename
|
// Otherwise use name as filename
|
||||||
@@ -2725,7 +2758,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If callback is set, modify image data object
|
// If callback is set, modify image data object
|
||||||
if (*WriteImageData != nullptr) {
|
if (*WriteImageData != nullptr && !filename.empty()) {
|
||||||
std::string uri;
|
std::string uri;
|
||||||
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
|
||||||
}
|
}
|
||||||
@@ -2970,7 +3003,9 @@ json_const_iterator ObjectEnd(const json &o) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *GetKey(json_const_iterator &it) {
|
// Making this a const char* results in a pointer to a temporary when
|
||||||
|
// TINYGLTF_USE_RAPIDJSON is off.
|
||||||
|
std::string GetKey(json_const_iterator &it) {
|
||||||
#ifdef TINYGLTF_USE_RAPIDJSON
|
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||||
return it->name.GetString();
|
return it->name.GetString();
|
||||||
#else
|
#else
|
||||||
@@ -3606,6 +3641,7 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o,
|
|||||||
ParseStringProperty(&asset->version, err, o, "version", true, "Asset");
|
ParseStringProperty(&asset->version, err, o, "version", true, "Asset");
|
||||||
ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset");
|
ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset");
|
||||||
ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset");
|
ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset");
|
||||||
|
ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset");
|
||||||
|
|
||||||
ParseExtensionsProperty(&asset->extensions, err, o);
|
ParseExtensionsProperty(&asset->extensions, err, o);
|
||||||
|
|
||||||
@@ -4855,6 +4891,13 @@ static bool ParseAnimationChannel(
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
ParseExtensionsProperty(&channel->target_extensions, err, target_object);
|
||||||
|
if (store_original_json_for_extras_and_extensions) {
|
||||||
|
json_const_iterator it;
|
||||||
|
if (FindMember(target_object, "extensions", it)) {
|
||||||
|
channel->target_extensions_json_string = JsonToString(GetValue(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->sampler = samplerIndex;
|
channel->sampler = samplerIndex;
|
||||||
@@ -5664,6 +5707,18 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
model->accessors[size_t(attribute.second)].bufferView)]
|
model->accessors[size_t(attribute.second)].bufferView)]
|
||||||
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &target : primitive.targets) {
|
||||||
|
for (auto &attribute : target) {
|
||||||
|
auto bufferView =
|
||||||
|
model->accessors[size_t(attribute.second)].bufferView;
|
||||||
|
// bufferView could be null(-1) for sparse morph target
|
||||||
|
if (bufferView >= 0) {
|
||||||
|
model->bufferViews[size_t(bufferView)].target =
|
||||||
|
TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6246,6 +6301,13 @@ static void SerializeNumberProperty(const std::string &key, T number,
|
|||||||
JsonAddMember(obj, key.c_str(), json(number));
|
JsonAddMember(obj, key.c_str(), json(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TINYGLTF_USE_RAPIDJSON
|
||||||
|
template <>
|
||||||
|
void SerializeNumberProperty(const std::string &key, size_t number, json &obj) {
|
||||||
|
JsonAddMember(obj, key.c_str(), json(static_cast<uint64_t>(number)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void SerializeNumberArrayProperty(const std::string &key,
|
static void SerializeNumberArrayProperty(const std::string &key,
|
||||||
const std::vector<T> &value,
|
const std::vector<T> &value,
|
||||||
@@ -6396,9 +6458,10 @@ static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
|
|||||||
const std::string &binFilename) {
|
const std::string &binFilename) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if defined(__GLIBCXX__) // mingw
|
#if defined(__GLIBCXX__) // mingw
|
||||||
int file_descriptor =
|
int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(),
|
||||||
_wopen(UTF8ToWchar(binFilename).c_str(), _O_WRONLY | _O_BINARY);
|
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||||
|
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||||
std::ostream output(&wfile_buf);
|
std::ostream output(&wfile_buf);
|
||||||
if (!wfile_buf.is_open()) return false;
|
if (!wfile_buf.is_open()) return false;
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
@@ -6481,9 +6544,10 @@ static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
||||||
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
if (accessor.bufferView >= 0)
|
||||||
|
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
|
||||||
|
|
||||||
if (accessor.byteOffset != 0.0)
|
if (accessor.byteOffset != 0)
|
||||||
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
SerializeNumberProperty<int>("byteOffset", int(accessor.byteOffset), o);
|
||||||
|
|
||||||
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
SerializeNumberProperty<int>("componentType", accessor.componentType, o);
|
||||||
@@ -6532,6 +6596,8 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
|||||||
SerializeNumberProperty("node", channel.target_node, target);
|
SerializeNumberProperty("node", channel.target_node, target);
|
||||||
SerializeStringProperty("path", channel.target_path, target);
|
SerializeStringProperty("path", channel.target_path, target);
|
||||||
|
|
||||||
|
SerializeExtensionMap(channel.target_extensions, target);
|
||||||
|
|
||||||
JsonAddMember(o, "target", std::move(target));
|
JsonAddMember(o, "target", std::move(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6571,6 +6637,7 @@ static void SerializeGltfAnimation(Animation &animation, json &o) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
json samplers;
|
json samplers;
|
||||||
|
JsonReserveArray(samplers, animation.samplers.size());
|
||||||
for (unsigned int i = 0; i < animation.samplers.size(); ++i) {
|
for (unsigned int i = 0; i < animation.samplers.size(); ++i) {
|
||||||
json sampler;
|
json sampler;
|
||||||
AnimationSampler gltfSampler = animation.samplers[i];
|
AnimationSampler gltfSampler = animation.samplers[i];
|
||||||
@@ -6936,7 +7003,9 @@ static void SerializeSpotLight(SpotLight &spot, json &o) {
|
|||||||
static void SerializeGltfLight(Light &light, json &o) {
|
static void SerializeGltfLight(Light &light, json &o) {
|
||||||
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
|
||||||
SerializeNumberProperty("intensity", light.intensity, o);
|
SerializeNumberProperty("intensity", light.intensity, o);
|
||||||
SerializeNumberProperty("range", light.range, o);
|
if (light.range > 0.0) {
|
||||||
|
SerializeNumberProperty("range", light.range, o);
|
||||||
|
}
|
||||||
SerializeNumberArrayProperty("color", light.color, o);
|
SerializeNumberArrayProperty("color", light.color, o);
|
||||||
SerializeStringProperty("type", light.type, o);
|
SerializeStringProperty("type", light.type, o);
|
||||||
if (light.type == "spot") {
|
if (light.type == "spot") {
|
||||||
@@ -7050,6 +7119,11 @@ static void SerializeGltfCamera(const Camera &camera, json &o) {
|
|||||||
} else {
|
} else {
|
||||||
// ???
|
// ???
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (camera.extras.Type() != NULL_TYPE) {
|
||||||
|
SerializeValue("extras", camera.extras, o);
|
||||||
|
}
|
||||||
|
SerializeExtensionMap(camera.extensions, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfScene(Scene &scene, json &o) {
|
static void SerializeGltfScene(Scene &scene, json &o) {
|
||||||
@@ -7096,14 +7170,16 @@ static void SerializeGltfTexture(Texture &texture, json &o) {
|
|||||||
///
|
///
|
||||||
static void SerializeGltfModel(Model *model, json &o) {
|
static void SerializeGltfModel(Model *model, json &o) {
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
json accessors;
|
if (model->accessors.size()) {
|
||||||
JsonReserveArray(accessors, model->accessors.size());
|
json accessors;
|
||||||
for (unsigned int i = 0; i < model->accessors.size(); ++i) {
|
JsonReserveArray(accessors, model->accessors.size());
|
||||||
json accessor;
|
for (unsigned int i = 0; i < model->accessors.size(); ++i) {
|
||||||
SerializeGltfAccessor(model->accessors[i], accessor);
|
json accessor;
|
||||||
JsonPushBack(accessors, std::move(accessor));
|
SerializeGltfAccessor(model->accessors[i], accessor);
|
||||||
|
JsonPushBack(accessors, std::move(accessor));
|
||||||
|
}
|
||||||
|
JsonAddMember(o, "accessors", std::move(accessors));
|
||||||
}
|
}
|
||||||
JsonAddMember(o, "accessors", std::move(accessors));
|
|
||||||
|
|
||||||
// ANIMATIONS
|
// ANIMATIONS
|
||||||
if (model->animations.size()) {
|
if (model->animations.size()) {
|
||||||
@@ -7126,18 +7202,15 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
JsonAddMember(o, "asset", std::move(asset));
|
JsonAddMember(o, "asset", std::move(asset));
|
||||||
|
|
||||||
// BUFFERVIEWS
|
// BUFFERVIEWS
|
||||||
json bufferViews;
|
if (model->bufferViews.size()) {
|
||||||
JsonReserveArray(bufferViews, model->bufferViews.size());
|
json bufferViews;
|
||||||
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
JsonReserveArray(bufferViews, model->bufferViews.size());
|
||||||
json bufferView;
|
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
|
||||||
SerializeGltfBufferView(model->bufferViews[i], bufferView);
|
json bufferView;
|
||||||
JsonPushBack(bufferViews, std::move(bufferView));
|
SerializeGltfBufferView(model->bufferViews[i], bufferView);
|
||||||
}
|
JsonPushBack(bufferViews, std::move(bufferView));
|
||||||
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
}
|
||||||
|
JsonAddMember(o, "bufferViews", std::move(bufferViews));
|
||||||
// Extensions used
|
|
||||||
if (model->extensionsUsed.size()) {
|
|
||||||
SerializeStringArrayProperty("extensionsUsed", model->extensionsUsed, o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extensions required
|
// Extensions required
|
||||||
@@ -7153,6 +7226,15 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
for (unsigned int i = 0; i < model->materials.size(); ++i) {
|
||||||
json material;
|
json material;
|
||||||
SerializeGltfMaterial(model->materials[i], material);
|
SerializeGltfMaterial(model->materials[i], material);
|
||||||
|
|
||||||
|
if (JsonIsNull(material)) {
|
||||||
|
// Issue 294.
|
||||||
|
// `material` does not have any required parameters
|
||||||
|
// so the result may be null(unmodified) when all material parameters have default value.
|
||||||
|
//
|
||||||
|
// null is not allowed thus we create an empty JSON object.
|
||||||
|
JsonSetObject(material);
|
||||||
|
}
|
||||||
JsonPushBack(materials, std::move(material));
|
JsonPushBack(materials, std::move(material));
|
||||||
}
|
}
|
||||||
JsonAddMember(o, "materials", std::move(materials));
|
JsonAddMember(o, "materials", std::move(materials));
|
||||||
@@ -7250,7 +7332,9 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
// EXTENSIONS
|
// EXTENSIONS
|
||||||
SerializeExtensionMap(model->extensions, o);
|
SerializeExtensionMap(model->extensions, o);
|
||||||
|
|
||||||
// LIGHTS as KHR_lights_cmn
|
auto extensionsUsed = model->extensionsUsed;
|
||||||
|
|
||||||
|
// LIGHTS as KHR_lights_punctual
|
||||||
if (model->lights.size()) {
|
if (model->lights.size()) {
|
||||||
json lights;
|
json lights;
|
||||||
JsonReserveArray(lights, model->lights.size());
|
JsonReserveArray(lights, model->lights.size());
|
||||||
@@ -7265,7 +7349,7 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
json_const_iterator it;
|
json_const_iterator it;
|
||||||
if (!FindMember(o, "extensions", it)) {
|
if (FindMember(o, "extensions", it)) {
|
||||||
JsonAssign(ext_j, GetValue(it));
|
JsonAssign(ext_j, GetValue(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7273,6 +7357,24 @@ static void SerializeGltfModel(Model *model, json &o) {
|
|||||||
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
|
||||||
|
|
||||||
JsonAddMember(o, "extensions", std::move(ext_j));
|
JsonAddMember(o, "extensions", std::move(ext_j));
|
||||||
|
|
||||||
|
// Also add "KHR_lights_punctual" to `extensionsUsed`
|
||||||
|
{
|
||||||
|
auto has_khr_lights_punctual =
|
||||||
|
std::find_if(extensionsUsed.begin(), extensionsUsed.end(),
|
||||||
|
[](const std::string &s) {
|
||||||
|
return (s.compare("KHR_lights_punctual") == 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (has_khr_lights_punctual == extensionsUsed.end()) {
|
||||||
|
extensionsUsed.push_back("KHR_lights_punctual");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extensions used
|
||||||
|
if (model->extensionsUsed.size()) {
|
||||||
|
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTRAS
|
// EXTRAS
|
||||||
@@ -7292,9 +7394,10 @@ static bool WriteGltfFile(const std::string &output,
|
|||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
|
||||||
#elif defined(__GLIBCXX__)
|
#elif defined(__GLIBCXX__)
|
||||||
int file_descriptor =
|
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
||||||
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||||
|
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||||
std::ostream gltfFile(&wfile_buf);
|
std::ostream gltfFile(&wfile_buf);
|
||||||
if (!wfile_buf.is_open()) return false;
|
if (!wfile_buf.is_open()) return false;
|
||||||
#else
|
#else
|
||||||
@@ -7380,9 +7483,10 @@ static void WriteBinaryGltfFile(const std::string &output,
|
|||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
|
||||||
#elif defined(__GLIBCXX__)
|
#elif defined(__GLIBCXX__)
|
||||||
int file_descriptor =
|
int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
|
||||||
_wopen(UTF8ToWchar(output).c_str(), _O_WRONLY | _O_BINARY);
|
_O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
|
||||||
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
|
__gnu_cxx::stdio_filebuf<char> wfile_buf(
|
||||||
|
file_descriptor, std::ios_base::out | std::ios_base::binary);
|
||||||
std::ostream gltfFile(&wfile_buf);
|
std::ostream gltfFile(&wfile_buf);
|
||||||
#else
|
#else
|
||||||
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
||||||
@@ -7402,20 +7506,21 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
SerializeGltfModel(model, output);
|
SerializeGltfModel(model, output);
|
||||||
|
|
||||||
// BUFFERS
|
// BUFFERS
|
||||||
std::vector<std::string> usedUris;
|
|
||||||
std::vector<unsigned char> binBuffer;
|
std::vector<unsigned char> binBuffer;
|
||||||
json buffers;
|
if (model->buffers.size()) {
|
||||||
JsonReserveArray(buffers, model->buffers.size());
|
json buffers;
|
||||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
JsonReserveArray(buffers, model->buffers.size());
|
||||||
json buffer;
|
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
json buffer;
|
||||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
||||||
} else {
|
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
||||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
} else {
|
||||||
|
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||||
|
}
|
||||||
|
JsonPushBack(buffers, std::move(buffer));
|
||||||
}
|
}
|
||||||
JsonPushBack(buffers, std::move(buffer));
|
JsonAddMember(output, "buffers", std::move(buffers));
|
||||||
}
|
}
|
||||||
JsonAddMember(output, "buffers", std::move(buffers));
|
|
||||||
|
|
||||||
// IMAGES
|
// IMAGES
|
||||||
if (model->images.size()) {
|
if (model->images.size()) {
|
||||||
@@ -7425,9 +7530,9 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
json image;
|
json image;
|
||||||
|
|
||||||
std::string dummystring = "";
|
std::string dummystring = "";
|
||||||
// UpdateImageObject need baseDir but only uses it if embededImages is
|
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
||||||
// enable, since we won't write separte images when writing to a stream we
|
// enabled, since we won't write separate images when writing to a stream
|
||||||
// use a dummystring
|
// we
|
||||||
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
||||||
&this->WriteImageData, this->write_image_user_data_);
|
&this->WriteImageData, this->write_image_user_data_);
|
||||||
SerializeGltfImage(model->images[i], image);
|
SerializeGltfImage(model->images[i], image);
|
||||||
@@ -7469,44 +7574,47 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|||||||
// BUFFERS
|
// BUFFERS
|
||||||
std::vector<std::string> usedUris;
|
std::vector<std::string> usedUris;
|
||||||
std::vector<unsigned char> binBuffer;
|
std::vector<unsigned char> binBuffer;
|
||||||
json buffers;
|
if (model->buffers.size()) {
|
||||||
JsonReserveArray(buffers, model->buffers.size());
|
json buffers;
|
||||||
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
JsonReserveArray(buffers, model->buffers.size());
|
||||||
json buffer;
|
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
|
||||||
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
json buffer;
|
||||||
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
|
||||||
} else if (embedBuffers) {
|
SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
|
||||||
SerializeGltfBuffer(model->buffers[i], buffer);
|
} else if (embedBuffers) {
|
||||||
} else {
|
SerializeGltfBuffer(model->buffers[i], buffer);
|
||||||
std::string binSavePath;
|
|
||||||
std::string binUri;
|
|
||||||
if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
|
|
||||||
binUri = model->buffers[i].uri;
|
|
||||||
} else {
|
} else {
|
||||||
binUri = defaultBinFilename + defaultBinFileExt;
|
std::string binSavePath;
|
||||||
bool inUse = true;
|
std::string binUri;
|
||||||
int numUsed = 0;
|
if (!model->buffers[i].uri.empty() &&
|
||||||
while (inUse) {
|
!IsDataURI(model->buffers[i].uri)) {
|
||||||
inUse = false;
|
binUri = model->buffers[i].uri;
|
||||||
for (const std::string &usedName : usedUris) {
|
} else {
|
||||||
if (binUri.compare(usedName) != 0) continue;
|
binUri = defaultBinFilename + defaultBinFileExt;
|
||||||
inUse = true;
|
bool inUse = true;
|
||||||
binUri = defaultBinFilename + std::to_string(numUsed++) +
|
int numUsed = 0;
|
||||||
defaultBinFileExt;
|
while (inUse) {
|
||||||
break;
|
inUse = false;
|
||||||
|
for (const std::string &usedName : usedUris) {
|
||||||
|
if (binUri.compare(usedName) != 0) continue;
|
||||||
|
inUse = true;
|
||||||
|
binUri = defaultBinFilename + std::to_string(numUsed++) +
|
||||||
|
defaultBinFileExt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
usedUris.push_back(binUri);
|
||||||
|
binSavePath = JoinPath(baseDir, binUri);
|
||||||
|
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
||||||
|
binUri)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
usedUris.push_back(binUri);
|
JsonPushBack(buffers, std::move(buffer));
|
||||||
binSavePath = JoinPath(baseDir, binUri);
|
|
||||||
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
|
|
||||||
binUri)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
JsonPushBack(buffers, std::move(buffer));
|
JsonAddMember(output, "buffers", std::move(buffers));
|
||||||
}
|
}
|
||||||
JsonAddMember(output, "buffers", std::move(buffers));
|
|
||||||
|
|
||||||
// IMAGES
|
// IMAGES
|
||||||
if (model->images.size()) {
|
if (model->images.size()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user