mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-13 18:58:53 +00:00
Compare commits
95 Commits
write-asse
...
glb-zero-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9fbc03e2d | ||
|
|
612e57816f | ||
|
|
a778c089d1 | ||
|
|
387fd61b83 | ||
|
|
6514490090 | ||
|
|
6b7ec9f494 | ||
|
|
c670f08a3b | ||
|
|
eec4c98862 | ||
|
|
c7e911cf11 | ||
|
|
43172238f7 | ||
|
|
0cc23356dc | ||
|
|
e413216722 | ||
|
|
4581d37bec | ||
|
|
966a9d0df7 | ||
|
|
64452bb5fa | ||
|
|
69eeea145b | ||
|
|
24e539621d | ||
|
|
f4f5c3cf3a | ||
|
|
b12a54ed15 | ||
|
|
240d993f94 | ||
|
|
46ee8b4276 | ||
|
|
3bddc09af4 | ||
|
|
9117abb45d | ||
|
|
52ff00a384 | ||
|
|
0fa56e239c | ||
|
|
5c2dd83964 | ||
|
|
1a8814d687 | ||
|
|
666ab8661c | ||
|
|
0b31543098 | ||
|
|
81f7dbe53a | ||
|
|
544969b732 | ||
|
|
3d4150419e | ||
|
|
41e1102e57 | ||
|
|
b901dd62d8 | ||
|
|
bc03ceaac1 | ||
|
|
2c9b25642b | ||
|
|
a894904f11 | ||
|
|
912856823d | ||
|
|
1a7c7d2001 | ||
|
|
fae6543b7a | ||
|
|
6ed7c39d71 | ||
|
|
5a90ab76ee | ||
|
|
0ffdc4334a | ||
|
|
53338352f2 | ||
|
|
d642c80a86 | ||
|
|
a1952053ee | ||
|
|
cbd3885049 | ||
|
|
9471517c1e | ||
|
|
e59028d68f | ||
|
|
cfab524125 | ||
|
|
9229971bcb | ||
|
|
051149311c | ||
|
|
0c7789b1e5 | ||
|
|
51b12d2546 | ||
|
|
4749b0989d | ||
|
|
0bfcb4f49e | ||
|
|
17e6e310ce | ||
|
|
07ceb4c313 | ||
|
|
e7f1ff5c59 | ||
|
|
fd904063c9 | ||
|
|
38398cc2da | ||
|
|
ed1a294bc4 | ||
|
|
b86eb6c079 | ||
|
|
e4bc6c7bd4 | ||
|
|
13803659f8 | ||
|
|
a3d5d5d1c9 | ||
|
|
9e3d1f6db5 | ||
|
|
190382aecd | ||
|
|
c6501530e3 | ||
|
|
ed48224f4b | ||
|
|
19a41d20ec | ||
|
|
0598a20cce | ||
|
|
514167b475 | ||
|
|
0f76561ebf | ||
|
|
f3dc4acaa4 | ||
|
|
1588e75e26 | ||
|
|
d1453b5e5e | ||
|
|
7e83ef9fb4 | ||
|
|
425195bf9c | ||
|
|
ce3a30e612 | ||
|
|
8a35b8f6fe | ||
|
|
f66f3bfeb3 | ||
|
|
e29ba7c49a | ||
|
|
bc753d4ac5 | ||
|
|
688ba8a60e | ||
|
|
d07b976d59 | ||
|
|
08a7dd8dad | ||
|
|
87da1e775f | ||
|
|
151495558e | ||
|
|
84e15260ba | ||
|
|
03cdef430d | ||
|
|
fb4bd82e2c | ||
|
|
3ddf8301f6 | ||
|
|
298c37a954 | ||
|
|
001c870051 |
6
.github/workflows/c-cpp.yml
vendored
6
.github/workflows/c-cpp.yml
vendored
@@ -47,7 +47,8 @@ jobs:
|
|||||||
sudo apt-get install -y mingw-w64
|
sudo apt-get install -y mingw-w64
|
||||||
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
|
x86_64-w64-mingw32-g++ -std=c++11 -o loader_example loader_example.cc
|
||||||
|
|
||||||
# Windows(x64) + Visual Studio 2019 build
|
# Windows(x64) + Visual Studio 2022 build
|
||||||
|
# Assume windows-latest have VS2022 installed
|
||||||
build-windows-msvc:
|
build-windows-msvc:
|
||||||
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
@@ -62,7 +63,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -G "Visual Studio 16 2019" -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
cmake --help
|
||||||
|
cmake -G "Visual Studio 17 2022" -A x64 -DTINYGLTF_BUILD_LOADER_EXAMPLE=On -DTINYGLTF_BUILD_GL_EXAMPLES=Off -DTINYGLTF_BUILD_VALIDATOR_EXAMPLE=On ..
|
||||||
cd ..
|
cd ..
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config Release
|
run: cmake --build build --config Release
|
||||||
|
|||||||
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ "master" ]
|
||||||
|
schedule:
|
||||||
|
- cron: '21 20 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'cpp', 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -68,4 +68,11 @@ loader_example
|
|||||||
tests/tester
|
tests/tester
|
||||||
tests/tester_noexcept
|
tests/tester_noexcept
|
||||||
tests/issue-97.gltf
|
tests/issue-97.gltf
|
||||||
|
tests/issue-261.gltf
|
||||||
|
|
||||||
|
# unignore
|
||||||
|
!Makefile
|
||||||
|
!examples/build-gltf/Makefile
|
||||||
|
!examples/raytrace/cornellbox_suzanne.obj
|
||||||
|
!tests/Makefile
|
||||||
|
!tools/windows/premake5.exe
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ PROJECT (tinygltf)
|
|||||||
|
|
||||||
SET(CMAKE_CXX_STANDARD 11)
|
SET(CMAKE_CXX_STANDARD 11)
|
||||||
|
|
||||||
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example" ON)
|
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
|
||||||
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
|
||||||
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator example" OFF)
|
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
|
||||||
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
|
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
|
||||||
|
option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF)
|
||||||
|
option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON)
|
||||||
|
|
||||||
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
if (TINYGLTF_BUILD_LOADER_EXAMPLE)
|
||||||
ADD_EXECUTABLE ( loader_example
|
ADD_EXECUTABLE ( loader_example
|
||||||
@@ -29,19 +31,46 @@ if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
|||||||
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
|
||||||
|
|
||||||
#
|
#
|
||||||
# TinuGLTF is a header-only library, so no library build. just install header files.
|
# for add_subdirectory and standalone build
|
||||||
#
|
#
|
||||||
INSTALL ( FILES
|
if (TINYGLTF_HEADER_ONLY)
|
||||||
json.hpp
|
add_library(tinygltf INTERFACE)
|
||||||
stb_image.h
|
|
||||||
stb_image_write.h
|
target_include_directories(tinygltf
|
||||||
tiny_gltf.h
|
INTERFACE
|
||||||
DESTINATION
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
include
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTALL ( FILES
|
else (TINYGLTF_HEADER_ONLY)
|
||||||
cmake/TinyGLTFConfig.cmake
|
add_library(tinygltf)
|
||||||
DESTINATION
|
target_sources(tinygltf PRIVATE
|
||||||
cmake
|
${CMAKE_CURRENT_SOURCE_DIR}/tiny_gltf.cc)
|
||||||
)
|
target_include_directories(tinygltf
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
|
)
|
||||||
|
endif (TINYGLTF_HEADER_ONLY)
|
||||||
|
|
||||||
|
if (TINYGLTF_INSTALL)
|
||||||
|
|
||||||
|
# Do not install .lib even if !TINYGLTF_HEADER_ONLY
|
||||||
|
|
||||||
|
INSTALL ( FILES
|
||||||
|
json.hpp
|
||||||
|
stb_image.h
|
||||||
|
stb_image_write.h
|
||||||
|
tiny_gltf.h
|
||||||
|
${TINYGLTF_EXTRA_SOUECES}
|
||||||
|
DESTINATION
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
INSTALL ( FILES
|
||||||
|
cmake/TinyGLTFConfig.cmake
|
||||||
|
DESTINATION
|
||||||
|
cmake
|
||||||
|
)
|
||||||
|
|
||||||
|
endif(TINYGLTF_INSTALL)
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -3,10 +3,15 @@
|
|||||||
`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.
|
||||||
|
(Also, you can use RadpidJSON as an JSON backend)
|
||||||
If you are looking for old, C++03 version, please use `devel-picojson` branch(but not maintained anymore).
|
If you are looking for old, C++03 version, please use `devel-picojson` branch(but not maintained anymore).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
Currently TinyGLTF is stable and maintainance mode. No drastic changes and feature additions planned.
|
||||||
|
|
||||||
|
- v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
|
||||||
|
- v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
||||||
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
|
- v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance)
|
||||||
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
|
- v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
|
||||||
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
|
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
|
||||||
@@ -15,7 +20,7 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch(bu
|
|||||||
|
|
||||||
### Branches
|
### Branches
|
||||||
|
|
||||||
* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson)
|
* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson), but not well maintained.
|
||||||
|
|
||||||
## Builds
|
## Builds
|
||||||
|
|
||||||
@@ -27,6 +32,8 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch(bu
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
Probably mostly feature-complete. Last missing feature is Draco encoding: https://github.com/syoyo/tinygltf/issues/207
|
||||||
|
|
||||||
* Written in portable C++. C++-11 with STL dependency only.
|
* Written in portable C++. C++-11 with STL dependency only.
|
||||||
* [x] macOS + clang(LLVM)
|
* [x] macOS + clang(LLVM)
|
||||||
* [x] iOS + clang
|
* [x] iOS + clang
|
||||||
@@ -92,11 +99,12 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
|||||||
* [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
|
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
|
||||||
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and proessional development of its developer
|
* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and proessional development of its developer
|
||||||
|
* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing
|
||||||
* Your projects here! (Please send PR)
|
* Your projects here! (Please send PR)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
|
* [ ] Robust URI decoding/encoding. https://github.com/syoyo/tinygltf/issues/369
|
||||||
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
* [ ] Mesh Compression/decompression(Open3DGC, etc)
|
||||||
* [x] Load Draco compressed mesh
|
* [x] Load Draco compressed mesh
|
||||||
* [ ] Save Draco compressed mesh
|
* [ ] Save Draco compressed mesh
|
||||||
@@ -107,6 +115,10 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
|
|||||||
* [ ] 16bit PNG support in Serialization
|
* [ ] 16bit PNG support in Serialization
|
||||||
* [ ] Write example and tests for `animation` and `skin`
|
* [ ] Write example and tests for `animation` and `skin`
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing?
|
||||||
|
|
||||||
## Licenses
|
## Licenses
|
||||||
|
|
||||||
TinyGLTF is licensed under MIT license.
|
TinyGLTF is licensed under MIT license.
|
||||||
@@ -170,11 +182,26 @@ if (!ret) {
|
|||||||
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
|
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
|
||||||
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
|
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
|
||||||
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||||
|
* `TINYGLTF_NO_INCLUDE_RAPIDJSON `: Disable including RapidJson's header files from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||||
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
|
||||||
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this featrure.
|
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this feature.
|
||||||
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
|
* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11.
|
||||||
|
|
||||||
|
## CMake options
|
||||||
|
|
||||||
|
You can add tinygltf using `add_subdirectory` feature.
|
||||||
|
If you add tinygltf to your project using `add_subdirectory`, it would be better to set `TINYGLTF_HEADER_ONLY` on(just add an include path to tinygltf) and `TINYGLTF_INSTALL` off(Which does not install tinygltf files).
|
||||||
|
|
||||||
|
```
|
||||||
|
// Your project's CMakeLists.txt
|
||||||
|
...
|
||||||
|
|
||||||
|
set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE)
|
||||||
|
set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE)
|
||||||
|
add_subdirectory(/path/to/tinygltf)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Saving gltTF 2.0 model
|
### Saving gltTF 2.0 model
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ bool loadModel(tinygltf::Model &model, const char *filename) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
void bindMesh(std::map<int, GLuint>& vbos,
|
||||||
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||||
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
|
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
|
||||||
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
const tinygltf::BufferView &bufferView = model.bufferViews[i];
|
||||||
if (bufferView.target == 0) { // TODO impl drawarrays
|
if (bufferView.target == 0) { // TODO impl drawarrays
|
||||||
@@ -144,12 +144,10 @@ std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vbos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind models
|
// bind models
|
||||||
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
void bindModelNodes(std::map<int, GLuint>& vbos, tinygltf::Model &model,
|
||||||
tinygltf::Node &node) {
|
tinygltf::Node &node) {
|
||||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||||
bindMesh(vbos, model, model.meshes[node.mesh]);
|
bindMesh(vbos, model, model.meshes[node.mesh]);
|
||||||
@@ -160,7 +158,8 @@ void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
|
|||||||
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GLuint bindModel(tinygltf::Model &model) {
|
|
||||||
|
std::pair<GLuint, std::map<int, GLuint>> bindModel(tinygltf::Model &model) {
|
||||||
std::map<int, GLuint> vbos;
|
std::map<int, GLuint> vbos;
|
||||||
GLuint vao;
|
GLuint vao;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
@@ -173,19 +172,29 @@ GLuint bindModel(tinygltf::Model &model) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
// cleanup vbos
|
// cleanup vbos but do not delete index buffers yet
|
||||||
for (size_t i = 0; i < vbos.size(); ++i) {
|
for (auto it = vbos.cbegin(); it != vbos.cend();) {
|
||||||
glDeleteBuffers(1, &vbos[i]);
|
tinygltf::BufferView bufferView = model.bufferViews[it->first];
|
||||||
|
if (bufferView.target != GL_ELEMENT_ARRAY_BUFFER) {
|
||||||
|
glDeleteBuffers(1, &vbos[it->first]);
|
||||||
|
vbos.erase(it++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vao;
|
return {vao, vbos};
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
void drawMesh(const std::map<int, GLuint>& vbos,
|
||||||
|
tinygltf::Model &model, tinygltf::Mesh &mesh) {
|
||||||
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
|
||||||
tinygltf::Primitive primitive = mesh.primitives[i];
|
tinygltf::Primitive primitive = mesh.primitives[i];
|
||||||
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos.at(indexAccessor.bufferView));
|
||||||
|
|
||||||
glDrawElements(primitive.mode, indexAccessor.count,
|
glDrawElements(primitive.mode, indexAccessor.count,
|
||||||
indexAccessor.componentType,
|
indexAccessor.componentType,
|
||||||
BUFFER_OFFSET(indexAccessor.byteOffset));
|
BUFFER_OFFSET(indexAccessor.byteOffset));
|
||||||
@@ -193,20 +202,22 @@ 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(const std::pair<GLuint, std::map<int, GLuint>>& vaoAndEbos,
|
||||||
|
tinygltf::Model &model, tinygltf::Node &node) {
|
||||||
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
|
||||||
drawMesh(model, model.meshes[node.mesh]);
|
drawMesh(vaoAndEbos.second, 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(vaoAndEbos, model, model.nodes[node.children[i]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void drawModel(GLuint vao, tinygltf::Model &model) {
|
void drawModel(const std::pair<GLuint, std::map<int, GLuint>>& vaoAndEbos,
|
||||||
glBindVertexArray(vao);
|
tinygltf::Model &model) {
|
||||||
|
glBindVertexArray(vaoAndEbos.first);
|
||||||
|
|
||||||
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
|
||||||
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
for (size_t i = 0; i < scene.nodes.size(); ++i) {
|
||||||
drawModelNodes(model, model.nodes[scene.nodes[i]]);
|
drawModelNodes(vaoAndEbos, model, model.nodes[scene.nodes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
@@ -282,7 +293,7 @@ void displayLoop(Window &window, const std::string &filename) {
|
|||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
if (!loadModel(model, filename.c_str())) return;
|
if (!loadModel(model, filename.c_str())) return;
|
||||||
|
|
||||||
GLuint vao = bindModel(model);
|
std::pair<GLuint, std::map<int, GLuint>> vaoAndEbos = bindModel(model);
|
||||||
// dbgModel(model); return;
|
// dbgModel(model); return;
|
||||||
|
|
||||||
// Model matrix : an identity matrix (model will be at the origin)
|
// Model matrix : an identity matrix (model will be at the origin)
|
||||||
@@ -317,10 +328,12 @@ void displayLoop(Window &window, const std::string &filename) {
|
|||||||
glUniform3fv(sun_position_u, 1, &sun_position[0]);
|
glUniform3fv(sun_position_u, 1, &sun_position[0]);
|
||||||
glUniform3fv(sun_color_u, 1, &sun_color[0]);
|
glUniform3fv(sun_color_u, 1, &sun_color[0]);
|
||||||
|
|
||||||
drawModel(vao, model);
|
drawModel(vaoAndEbos, model);
|
||||||
glfwSwapBuffers(window.window);
|
glfwSwapBuffers(window.window);
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glDeleteVertexArrays(1, &vaoAndEbos.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error_callback(int error, const char *description) {
|
static void error_callback(int error, const char *description) {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ if (DEFINED DRACO_DIR)
|
|||||||
# TODO(syoyo): better CMake script for draco
|
# TODO(syoyo): better CMake script for draco
|
||||||
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
add_definitions(-DTINYGLTF_ENABLE_DRACO)
|
||||||
include_directories(${DRACO_DIR}/include)
|
include_directories(${DRACO_DIR}/include)
|
||||||
|
|
||||||
link_directories(${DRACO_DIR}/lib)
|
link_directories(${DRACO_DIR}/lib)
|
||||||
set(DRACO_LIBRARY draco)
|
set(DRACO_LIBRARY draco)
|
||||||
endif ()
|
endif ()
|
||||||
@@ -49,9 +49,9 @@ add_executable(glview
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries ( glview
|
target_link_libraries ( glview
|
||||||
${DRACO_LIBRARY}
|
${DRACO_LIBRARY}
|
||||||
${GLFW3_UNIX_LINK_LIBRARIES}
|
${GLFW3_UNIX_LINK_LIBRARIES}
|
||||||
${GLEW_LIBRARY}
|
${GLEW_LIBRARIES}
|
||||||
${GLFW3_glfw_LIBRARY}
|
${GLFW3_glfw_LIBRARY}
|
||||||
${OPENGL_gl_LIBRARY}
|
${OPENGL_gl_LIBRARY}
|
||||||
${OPENGL_glu_LIBRARY}
|
${OPENGL_glu_LIBRARY}
|
||||||
|
|||||||
@@ -771,6 +771,30 @@ static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void QuatToAngleAxis(const std::vector<double> quaternion,
|
||||||
|
double &outAngleDegrees,
|
||||||
|
double *axis) {
|
||||||
|
double qx = quaternion[0];
|
||||||
|
double qy = quaternion[1];
|
||||||
|
double qz = quaternion[2];
|
||||||
|
double qw = quaternion[3];
|
||||||
|
|
||||||
|
double angleRadians = 2 * acos(qw);
|
||||||
|
if (angleRadians == 0.0) {
|
||||||
|
outAngleDegrees = 0.0;
|
||||||
|
axis[0] = 0.0;
|
||||||
|
axis[1] = 0.0;
|
||||||
|
axis[2] = 1.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double denom = sqrt(1-qw*qw);
|
||||||
|
outAngleDegrees = angleRadians * 180.0 / M_PI;
|
||||||
|
axis[0] = qx / denom;
|
||||||
|
axis[1] = qy / denom;
|
||||||
|
axis[2] = qz / denom;
|
||||||
|
}
|
||||||
|
|
||||||
// Hierarchically draw nodes
|
// Hierarchically draw nodes
|
||||||
static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
||||||
// Apply xform
|
// Apply xform
|
||||||
@@ -781,18 +805,22 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) {
|
|||||||
glMultMatrixd(node.matrix.data());
|
glMultMatrixd(node.matrix.data());
|
||||||
} else {
|
} else {
|
||||||
// Assume Trans x Rotate x Scale order
|
// Assume Trans x Rotate x Scale order
|
||||||
if (node.scale.size() == 3) {
|
|
||||||
glScaled(node.scale[0], node.scale[1], node.scale[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.rotation.size() == 4) {
|
|
||||||
glRotated(node.rotation[0], node.rotation[1], node.rotation[2],
|
|
||||||
node.rotation[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.translation.size() == 3) {
|
if (node.translation.size() == 3) {
|
||||||
glTranslated(node.translation[0], node.translation[1],
|
glTranslated(node.translation[0], node.translation[1],
|
||||||
node.translation[2]);
|
node.translation[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.rotation.size() == 4) {
|
||||||
|
double angleDegrees;
|
||||||
|
double axis[3];
|
||||||
|
|
||||||
|
QuatToAngleAxis(node.rotation, angleDegrees, axis);
|
||||||
|
|
||||||
|
glRotated(angleDegrees, axis[0], axis[1], axis[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.scale.size() == 3) {
|
||||||
|
glScaled(node.scale[0], node.scale[1], node.scale[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ static void Dump(const tinygltf::Model &model) {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
std::cout << Indent(1) << "channels : [ " << std::endl;
|
std::cout << Indent(1) << "channels : [ " << std::endl;
|
||||||
for (size_t j = 0; i < animation.channels.size(); i++) {
|
for (size_t j = 0; j < animation.channels.size(); j++) {
|
||||||
std::cout << Indent(2)
|
std::cout << Indent(2)
|
||||||
<< "sampler : " << animation.channels[j].sampler
|
<< "sampler : " << animation.channels[j].sampler
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|||||||
267
models/regression/unassigned-skeleton.gltf
Normal file
267
models/regression/unassigned-skeleton.gltf
Normal file
File diff suppressed because one or more lines are too long
@@ -436,6 +436,36 @@ TEST_CASE("serialize-empty-material", "[issue-294]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("empty-skeleton-id", "[issue-321]") {
|
||||||
|
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/regression/unassigned-skeleton.gltf");
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
|
||||||
|
REQUIRE(model.skins.size() == 1);
|
||||||
|
REQUIRE(model.skins[0].skeleton == -1); // unassigned
|
||||||
|
|
||||||
|
std::stringstream os;
|
||||||
|
|
||||||
|
ctx.WriteGltfSceneToStream(&model, os, false, false);
|
||||||
|
|
||||||
|
// use nlohmann json
|
||||||
|
nlohmann::json j = nlohmann::json::parse(os.str());
|
||||||
|
|
||||||
|
// Ensure `skeleton` property is not written to .gltf(was serialized as -1)
|
||||||
|
REQUIRE(1 == j["skins"].size());
|
||||||
|
REQUIRE(j["skins"][0].is_object());
|
||||||
|
REQUIRE(j["skins"][0].count("skeleton") == 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TINYGLTF_NO_FS
|
#ifndef TINYGLTF_NO_FS
|
||||||
TEST_CASE("expandpath-utf-8", "[pr-226]") {
|
TEST_CASE("expandpath-utf-8", "[pr-226]") {
|
||||||
|
|
||||||
@@ -452,3 +482,61 @@ TEST_CASE("expandpath-utf-8", "[pr-226]") {
|
|||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST_CASE("empty-bin-buffer", "[issue-382]") {
|
||||||
|
tinygltf::Model model;
|
||||||
|
tinygltf::TinyGLTF ctx;
|
||||||
|
std::string err;
|
||||||
|
std::string warn;
|
||||||
|
|
||||||
|
tinygltf::Model model_empty;
|
||||||
|
std::stringstream stream;
|
||||||
|
bool ret = ctx.WriteGltfSceneToStream(&model_empty, stream, false, true);
|
||||||
|
REQUIRE(ret == true);
|
||||||
|
std::string str = stream.str();
|
||||||
|
const unsigned char* bytes = (unsigned char*)str.data();
|
||||||
|
ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, bytes, str.size());
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
|
||||||
|
err.clear();
|
||||||
|
warn.clear();
|
||||||
|
|
||||||
|
tinygltf::Model model_empty_buffer;
|
||||||
|
model_empty_buffer.buffers.push_back(tinygltf::Buffer());
|
||||||
|
stream = std::stringstream();
|
||||||
|
ret = ctx.WriteGltfSceneToStream(&model_empty_buffer, stream, false, true);
|
||||||
|
REQUIRE(ret == true);
|
||||||
|
str = stream.str();
|
||||||
|
bytes = (unsigned char*)str.data();
|
||||||
|
ret = ctx.LoadBinaryFromMemory(&model, &err, &warn, bytes, str.size());
|
||||||
|
if (err.empty()) {
|
||||||
|
std::cerr << "there should have been an error reported" << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(false == ret);
|
||||||
|
|
||||||
|
err.clear();
|
||||||
|
warn.clear();
|
||||||
|
|
||||||
|
tinygltf::Model model_single_byte_buffer;
|
||||||
|
tinygltf::Buffer buffer;
|
||||||
|
buffer.data.push_back(0);
|
||||||
|
model_single_byte_buffer.buffers.push_back(buffer);
|
||||||
|
stream = std::stringstream();
|
||||||
|
ret = ctx.WriteGltfSceneToStream(&model_single_byte_buffer, stream, false, true);
|
||||||
|
REQUIRE(ret == true);
|
||||||
|
str = stream.str();
|
||||||
|
{
|
||||||
|
std::ofstream ofs("tmp.glb");
|
||||||
|
ofs.write(str.data(), str.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = (unsigned char*)str.data();
|
||||||
|
ret = ctx.LoadBinaryFromMemory(&model_single_byte_buffer, &err, &warn, bytes, str.size());
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
}
|
||||||
|
REQUIRE(true == ret);
|
||||||
|
}
|
||||||
|
|||||||
4
tiny_gltf.cc
Normal file
4
tiny_gltf.cc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#define TINYGLTF_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "tiny_gltf.h"
|
||||||
436
tiny_gltf.h
436
tiny_gltf.h
@@ -26,6 +26,10 @@
|
|||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
|
|
||||||
// Version:
|
// Version:
|
||||||
|
// - v2.6.2 Fix out-of-bounds access of accessors. PR#379.
|
||||||
|
// - v2.6.1 Better GLB validation check when loading.
|
||||||
|
// - v2.6.0 Support serializing sparse accessor(Thanks to @fynv).
|
||||||
|
// Disable expanding file path for security(no use of awkward `wordexp` anymore).
|
||||||
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
|
||||||
// - v2.4.3 Fix null object output when when material has all default
|
// - v2.4.3 Fix null object output when when material has all default
|
||||||
// parameters.
|
// parameters.
|
||||||
@@ -64,6 +68,11 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
//Auto-detect C++14 standard version
|
||||||
|
#if !defined(TINYGLTF_USE_CPP14) && defined(__cplusplus) && (__cplusplus >= 201402L)
|
||||||
|
#define TINYGLTF_USE_CPP14
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TINYGLTF_USE_CPP14
|
#ifndef TINYGLTF_USE_CPP14
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#endif
|
#endif
|
||||||
@@ -108,7 +117,11 @@ namespace tinygltf {
|
|||||||
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
|
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
|
||||||
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
|
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
|
||||||
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
|
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
|
||||||
#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5130)
|
#define TINYGLTF_COMPONENT_TYPE_DOUBLE \
|
||||||
|
(5130) // OpenGL double type. Note that some of glTF 2.0 validator does not
|
||||||
|
// support double type even the schema seems allow any value of
|
||||||
|
// integer:
|
||||||
|
// https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22
|
||||||
|
|
||||||
#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
|
#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
|
||||||
#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
|
#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
|
||||||
@@ -191,14 +204,14 @@ AAssetManager *asset_manager = nullptr;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NULL_TYPE = 0,
|
NULL_TYPE,
|
||||||
REAL_TYPE = 1,
|
REAL_TYPE,
|
||||||
INT_TYPE = 2,
|
INT_TYPE,
|
||||||
BOOL_TYPE = 3,
|
BOOL_TYPE,
|
||||||
STRING_TYPE = 4,
|
STRING_TYPE,
|
||||||
ARRAY_TYPE = 5,
|
ARRAY_TYPE,
|
||||||
BINARY_TYPE = 6,
|
BINARY_TYPE,
|
||||||
OBJECT_TYPE = 7
|
OBJECT_TYPE
|
||||||
} Type;
|
} Type;
|
||||||
|
|
||||||
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
|
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
|
||||||
@@ -253,7 +266,6 @@ bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
|
|||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
// Suppress warning for : static Value null_value
|
// Suppress warning for : static Value null_value
|
||||||
// https://stackoverflow.com/questions/15708411/how-to-deal-with-global-constructor-warning-in-clang
|
|
||||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||||
#pragma clang diagnostic ignored "-Wpadded"
|
#pragma clang diagnostic ignored "-Wpadded"
|
||||||
#endif
|
#endif
|
||||||
@@ -604,7 +616,7 @@ struct Sampler {
|
|||||||
// `magFilter`. Set -1 in TinyGLTF(issue #186)
|
// `magFilter`. Set -1 in TinyGLTF(issue #186)
|
||||||
int minFilter =
|
int minFilter =
|
||||||
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
|
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
|
||||||
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST",
|
// "NEAREST_MIPMAP_NEAREST", "LINEAR_MIPMAP_NEAREST",
|
||||||
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
|
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
|
||||||
int magFilter =
|
int magFilter =
|
||||||
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
|
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
|
||||||
@@ -614,7 +626,8 @@ struct Sampler {
|
|||||||
int wrapT =
|
int wrapT =
|
||||||
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
|
TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
|
||||||
// "REPEAT"], default "REPEAT"
|
// "REPEAT"], default "REPEAT"
|
||||||
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently not used.
|
// int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently
|
||||||
|
// not used.
|
||||||
|
|
||||||
Value extras;
|
Value extras;
|
||||||
ExtensionMap extensions;
|
ExtensionMap extensions;
|
||||||
@@ -1303,8 +1316,10 @@ class TinyGLTF {
|
|||||||
///
|
///
|
||||||
/// Loads glTF ASCII asset from string(memory).
|
/// Loads glTF ASCII asset from string(memory).
|
||||||
/// `length` = strlen(str);
|
/// `length` = strlen(str);
|
||||||
/// Set warning message to `warn` for example it fails to load asserts.
|
/// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// expanded path (e.g. no tilde(`~`), no environment variables). Set warning
|
||||||
|
/// message to `warn` for example it fails to load asserts. Returns false and
|
||||||
|
/// set error string to `err` if there's an error.
|
||||||
///
|
///
|
||||||
bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn,
|
bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn,
|
||||||
const char *str, const unsigned int length,
|
const char *str, const unsigned int length,
|
||||||
@@ -1323,6 +1338,8 @@ class TinyGLTF {
|
|||||||
///
|
///
|
||||||
/// Loads glTF binary asset from memory.
|
/// Loads glTF binary asset from memory.
|
||||||
/// `length` = strlen(str);
|
/// `length` = strlen(str);
|
||||||
|
/// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
|
||||||
|
/// expanded path (e.g. no tilde(`~`), no environment variables).
|
||||||
/// Set warning message to `warn` for example it fails to load asserts.
|
/// Set warning message to `warn` for example it fails to load asserts.
|
||||||
/// Returns false and set error string to `err` if there's an error.
|
/// Returns false and set error string to `err` if there's an error.
|
||||||
///
|
///
|
||||||
@@ -1425,6 +1442,10 @@ class TinyGLTF {
|
|||||||
bool preserve_image_channels_ = false; /// Default false(expand channels to
|
bool preserve_image_channels_ = false; /// Default false(expand channels to
|
||||||
/// RGBA) for backward compatibility.
|
/// RGBA) for backward compatibility.
|
||||||
|
|
||||||
|
// Warning & error messages
|
||||||
|
std::string warn_;
|
||||||
|
std::string err_;
|
||||||
|
|
||||||
FsCallbacks fs = {
|
FsCallbacks fs = {
|
||||||
#ifndef TINYGLTF_NO_FS
|
#ifndef TINYGLTF_NO_FS
|
||||||
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
|
&tinygltf::FileExists, &tinygltf::ExpandFilePath,
|
||||||
@@ -1538,6 +1559,7 @@ class TinyGLTF {
|
|||||||
#ifndef TINYGLTF_USE_RAPIDJSON
|
#ifndef TINYGLTF_USE_RAPIDJSON
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#else
|
#else
|
||||||
|
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "prettywriter.h"
|
#include "prettywriter.h"
|
||||||
#include "rapidjson.h"
|
#include "rapidjson.h"
|
||||||
@@ -1545,6 +1567,7 @@ class TinyGLTF {
|
|||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TINYGLTF_ENABLE_DRACO
|
#ifdef TINYGLTF_ENABLE_DRACO
|
||||||
#include "draco/compression/decode.h"
|
#include "draco/compression/decode.h"
|
||||||
@@ -1603,11 +1626,11 @@ class TinyGLTF {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif !defined(__ANDROID__)
|
#elif !defined(__ANDROID__) && !defined(__OpenBSD__)
|
||||||
#include <wordexp.h>
|
//#include <wordexp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__sparcv9)
|
#if defined(__sparcv9) || defined(__powerpc__)
|
||||||
// Big endian
|
// Big endian
|
||||||
#else
|
#else
|
||||||
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
|
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
|
||||||
@@ -1932,9 +1955,9 @@ bool Sampler::operator==(const Sampler &other) const {
|
|||||||
return this->extensions == other.extensions && this->extras == other.extras &&
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
||||||
this->magFilter == other.magFilter &&
|
this->magFilter == other.magFilter &&
|
||||||
this->minFilter == other.minFilter && this->name == other.name &&
|
this->minFilter == other.minFilter && this->name == other.name &&
|
||||||
this->wrapT == other.wrapT;
|
this->wrapS == other.wrapS && this->wrapT == other.wrapT;
|
||||||
|
|
||||||
//this->wrapR == other.wrapR && this->wrapS == other.wrapS &&
|
// this->wrapR == other.wrapR
|
||||||
}
|
}
|
||||||
bool Scene::operator==(const Scene &other) const {
|
bool Scene::operator==(const Scene &other) const {
|
||||||
return this->extensions == other.extensions && this->extras == other.extras &&
|
return this->extensions == other.extensions && this->extras == other.extras &&
|
||||||
@@ -2038,9 +2061,10 @@ static std::string GetBaseDir(const std::string &filepath) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
|
|
||||||
static std::string GetBaseFilename(const std::string &filepath) {
|
static std::string GetBaseFilename(const std::string &filepath) {
|
||||||
return filepath.substr(filepath.find_last_of("/\\") + 1);
|
auto idx = filepath.find_last_of("/\\");
|
||||||
|
if (idx != std::string::npos) return filepath.substr(idx + 1);
|
||||||
|
return filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string base64_encode(unsigned char const *, unsigned int len);
|
std::string base64_encode(unsigned char const *, unsigned int len);
|
||||||
@@ -2186,47 +2210,35 @@ std::string base64_decode(std::string const &encoded_string) {
|
|||||||
// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri
|
// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri
|
||||||
// decoding?
|
// decoding?
|
||||||
//
|
//
|
||||||
// https://stackoverflow.com/questions/18307429/encode-decode-url-in-c
|
// Uri Decoding from DLIB
|
||||||
// http://dlib.net/dlib/server/server_http.cpp.html
|
// http://dlib.net/dlib/server/server_http.cpp.html
|
||||||
|
// --- dlib begin ------------------------------------------------------------
|
||||||
// --- dlib beign ------------------------------------------------------------
|
|
||||||
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
||||||
// License: Boost Software License See LICENSE.txt for the full license.
|
// License: Boost Software License
|
||||||
|
// Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
// Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
// obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
// this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
// execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
// Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
// do so, all subject to the following:
|
||||||
|
// The copyright notices in the Software and this entire statement, including
|
||||||
|
// the above license grant, this restriction and the following disclaimer,
|
||||||
|
// must be included in all copies of the Software, in whole or in part, and
|
||||||
|
// all derivative works of the Software, unless such copies or derivative
|
||||||
|
// works are solely in the form of machine-executable object code generated by
|
||||||
|
// a source language processor.
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
namespace dlib {
|
namespace dlib {
|
||||||
|
|
||||||
#if 0
|
|
||||||
inline unsigned char to_hex( unsigned char x )
|
|
||||||
{
|
|
||||||
return x + (x > 9 ? ('A'-10) : '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string urlencode( const std::string& s )
|
|
||||||
{
|
|
||||||
std::ostringstream os;
|
|
||||||
|
|
||||||
for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci )
|
|
||||||
{
|
|
||||||
if ( (*ci >= 'a' && *ci <= 'z') ||
|
|
||||||
(*ci >= 'A' && *ci <= 'Z') ||
|
|
||||||
(*ci >= '0' && *ci <= '9') )
|
|
||||||
{ // allowed
|
|
||||||
os << *ci;
|
|
||||||
}
|
|
||||||
else if ( *ci == ' ')
|
|
||||||
{
|
|
||||||
os << '+';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
os << '%' << to_hex(static_cast<unsigned char>(*ci >> 4)) << to_hex(static_cast<unsigned char>(*ci % 16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.str();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline unsigned char from_hex(unsigned char ch) {
|
inline unsigned char from_hex(unsigned char ch) {
|
||||||
if (ch <= '9' && ch >= '0')
|
if (ch <= '9' && ch >= '0')
|
||||||
ch -= '0';
|
ch -= '0';
|
||||||
@@ -2613,6 +2625,18 @@ bool FileExists(const std::string &abs_filename, void *) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string ExpandFilePath(const std::string &filepath, void *) {
|
std::string ExpandFilePath(const std::string &filepath, void *) {
|
||||||
|
// https://github.com/syoyo/tinygltf/issues/368
|
||||||
|
//
|
||||||
|
// No file path expansion in built-in FS function anymore, since glTF URI
|
||||||
|
// should not contain tilde('~') and environment variables, and for security
|
||||||
|
// reason(`wordexp`).
|
||||||
|
//
|
||||||
|
// Users need to supply `base_dir`(in `LoadASCIIFromString`,
|
||||||
|
// `LoadBinaryFromMemory`) in expanded absolute path.
|
||||||
|
|
||||||
|
return filepath;
|
||||||
|
|
||||||
|
#if 0
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Assume input `filepath` is encoded in UTF-8
|
// Assume input `filepath` is encoded in UTF-8
|
||||||
std::wstring wfilepath = UTF8ToWchar(filepath);
|
std::wstring wfilepath = UTF8ToWchar(filepath);
|
||||||
@@ -2627,7 +2651,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
|
||||||
defined(__ANDROID__) || defined(__EMSCRIPTEN__)
|
defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__OpenBSD__)
|
||||||
// no expansion
|
// no expansion
|
||||||
std::string s = filepath;
|
std::string s = filepath;
|
||||||
#else
|
#else
|
||||||
@@ -2660,6 +2684,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) {
|
|||||||
|
|
||||||
return s;
|
return s;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
|
||||||
@@ -3100,11 +3125,17 @@ std::string JsonToString(const json &o, int spacing = -1) {
|
|||||||
StringBuffer buffer;
|
StringBuffer buffer;
|
||||||
if (spacing == -1) {
|
if (spacing == -1) {
|
||||||
Writer<StringBuffer> writer(buffer);
|
Writer<StringBuffer> writer(buffer);
|
||||||
o.Accept(writer);
|
// TODO: Better error handling.
|
||||||
|
// https://github.com/syoyo/tinygltf/issues/332
|
||||||
|
if (!o.Accept(writer)) {
|
||||||
|
return "tiny_gltf::JsonToString() failed rapidjson conversion";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PrettyWriter<StringBuffer> writer(buffer);
|
PrettyWriter<StringBuffer> writer(buffer);
|
||||||
writer.SetIndent(' ', uint32_t(spacing));
|
writer.SetIndent(' ', uint32_t(spacing));
|
||||||
o.Accept(writer);
|
if (!o.Accept(writer)) {
|
||||||
|
return "tiny_gltf::JsonToString() failed rapidjson conversion";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return buffer.GetString();
|
return buffer.GetString();
|
||||||
#else
|
#else
|
||||||
@@ -3200,13 +3231,16 @@ static bool ParseJsonAsValue(Value *ret, const json &o) {
|
|||||||
break;
|
break;
|
||||||
case json::value_t::null:
|
case json::value_t::null:
|
||||||
case json::value_t::discarded:
|
case json::value_t::discarded:
|
||||||
|
case json::value_t::binary:
|
||||||
// default:
|
// default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
const bool isNotNull = val.Type() != NULL_TYPE;
|
||||||
|
|
||||||
if (ret) *ret = std::move(val);
|
if (ret) *ret = std::move(val);
|
||||||
|
|
||||||
return val.Type() != NULL_TYPE;
|
return isNotNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ParseExtrasProperty(Value *ret, const json &o) {
|
static bool ParseExtrasProperty(Value *ret, const json &o) {
|
||||||
@@ -3646,7 +3680,8 @@ static bool ParseParameterProperty(Parameter *param, std::string *err,
|
|||||||
// Found a number array.
|
// Found a number array.
|
||||||
return true;
|
return true;
|
||||||
} else if (ParseNumberProperty(¶m->number_value, err, o, prop, false)) {
|
} else if (ParseNumberProperty(¶m->number_value, err, o, prop, false)) {
|
||||||
return param->has_number_value = true;
|
param->has_number_value = true;
|
||||||
|
return true;
|
||||||
} else if (ParseJSONProperty(¶m->json_double_value, err, o, prop,
|
} else if (ParseJSONProperty(¶m->json_double_value, err, o, prop,
|
||||||
false)) {
|
false)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -3839,7 +3874,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|||||||
image->uri = uri;
|
image->uri = uri;
|
||||||
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#else
|
||||||
std::string decoded_uri = dlib::urldecode(uri);
|
std::string decoded_uri = dlib::urldecode(uri);
|
||||||
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
|
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
|
||||||
/* required */ false, /* required bytes */ 0,
|
/* required */ false, /* required bytes */ 0,
|
||||||
@@ -3861,6 +3896,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*LoadImageData == nullptr) {
|
if (*LoadImageData == nullptr) {
|
||||||
@@ -4077,7 +4113,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
|||||||
|
|
||||||
if ((bin_size == 0) || (bin_data == nullptr)) {
|
if ((bin_size == 0) || (bin_data == nullptr)) {
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) += "Invalid binary data in `Buffer'.\n";
|
(*err) += "Invalid binary data in `Buffer', or GLB with empty BIN chunk.\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -4223,7 +4259,9 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
accessor->sparse.isSparse = true;
|
accessor->sparse.isSparse = true;
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
ParseIntegerProperty(&count, err, o, "count", true);
|
if (!ParseIntegerProperty(&count, err, o, "count", true, "SparseAccessor")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
json_const_iterator indices_iterator;
|
json_const_iterator indices_iterator;
|
||||||
json_const_iterator values_iterator;
|
json_const_iterator values_iterator;
|
||||||
@@ -4241,18 +4279,24 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
const json &values_obj = GetValue(values_iterator);
|
const json &values_obj = GetValue(values_iterator);
|
||||||
|
|
||||||
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
|
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
|
||||||
ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj,
|
||||||
true);
|
"bufferView", true, "SparseAccessor")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||||
true);
|
false);
|
||||||
ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
||||||
true);
|
true, "SparseAccessor")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int values_buffer_view = 0, values_byte_offset = 0;
|
int values_buffer_view = 0, values_byte_offset = 0;
|
||||||
ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
||||||
true);
|
true, "SparseAccessor")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
|
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
|
||||||
true);
|
false);
|
||||||
|
|
||||||
accessor->sparse.count = count;
|
accessor->sparse.count = count;
|
||||||
accessor->sparse.indices.bufferView = indices_buffer_view;
|
accessor->sparse.indices.bufferView = indices_buffer_view;
|
||||||
@@ -4261,8 +4305,6 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
|||||||
accessor->sparse.values.bufferView = values_buffer_view;
|
accessor->sparse.values.bufferView = values_buffer_view;
|
||||||
accessor->sparse.values.byteOffset = values_byte_offset;
|
accessor->sparse.values.byteOffset = values_byte_offset;
|
||||||
|
|
||||||
// todo check theses values
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4470,6 +4512,7 @@ static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh,
|
|||||||
static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
||||||
std::string *err,
|
std::string *err,
|
||||||
const Value &dracoExtensionValue) {
|
const Value &dracoExtensionValue) {
|
||||||
|
(void)err;
|
||||||
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
|
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
|
||||||
if (!bufferViewValue.IsInt()) return false;
|
if (!bufferViewValue.IsInt()) return false;
|
||||||
auto attributesValue = dracoExtensionValue.Get("attributes");
|
auto attributesValue = dracoExtensionValue.Get("attributes");
|
||||||
@@ -4530,7 +4573,6 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
|||||||
|
|
||||||
int dracoAttributeIndex = attribute.second.Get<int>();
|
int dracoAttributeIndex = attribute.second.Get<int>();
|
||||||
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
|
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
|
||||||
const auto pBuffer = pAttribute->buffer();
|
|
||||||
const auto componentType =
|
const auto componentType =
|
||||||
model->accessors[primitiveAttribute->second].componentType;
|
model->accessors[primitiveAttribute->second].componentType;
|
||||||
|
|
||||||
@@ -5089,12 +5131,13 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|||||||
int magFilter = -1;
|
int magFilter = -1;
|
||||||
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
//int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
// int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||||
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
||||||
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
||||||
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
||||||
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
||||||
//ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension
|
// ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf
|
||||||
|
// extension
|
||||||
|
|
||||||
// TODO(syoyo): Check the value is alloed one.
|
// TODO(syoyo): Check the value is alloed one.
|
||||||
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
|
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
|
||||||
@@ -5103,7 +5146,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
|
|||||||
sampler->magFilter = magFilter;
|
sampler->magFilter = magFilter;
|
||||||
sampler->wrapS = wrapS;
|
sampler->wrapS = wrapS;
|
||||||
sampler->wrapT = wrapT;
|
sampler->wrapT = wrapT;
|
||||||
//sampler->wrapR = wrapR;
|
// sampler->wrapR = wrapR;
|
||||||
|
|
||||||
ParseExtensionsProperty(&(sampler->extensions), err, o);
|
ParseExtensionsProperty(&(sampler->extensions), err, o);
|
||||||
ParseExtrasProperty(&(sampler->extras), o);
|
ParseExtrasProperty(&(sampler->extras), o);
|
||||||
@@ -5762,20 +5805,27 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto &attribute : primitive.attributes) {
|
for (auto &attribute : primitive.attributes) {
|
||||||
model
|
const auto accessorsIndex = size_t(attribute.second);
|
||||||
->bufferViews[size_t(
|
if (accessorsIndex < model->accessors.size()) {
|
||||||
model->accessors[size_t(attribute.second)].bufferView)]
|
const auto bufferView = model->accessors[accessorsIndex].bufferView;
|
||||||
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
|
// bufferView could be null(-1) for sparse morph target
|
||||||
|
if (bufferView >= 0 && bufferView < model->bufferViews.size()) {
|
||||||
|
model->bufferViews[size_t(bufferView)].target =
|
||||||
|
TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &target : primitive.targets) {
|
for (auto &target : primitive.targets) {
|
||||||
for (auto &attribute : target) {
|
for (auto &attribute : target) {
|
||||||
auto bufferView =
|
const auto accessorsIndex = size_t(attribute.second);
|
||||||
model->accessors[size_t(attribute.second)].bufferView;
|
if (accessorsIndex < model->accessors.size()) {
|
||||||
// bufferView could be null(-1) for sparse morph target
|
const auto bufferView = model->accessors[accessorsIndex].bufferView;
|
||||||
if (bufferView >= 0) {
|
// bufferView could be null(-1) for sparse morph target
|
||||||
model->bufferViews[size_t(bufferView)].target =
|
if (bufferView >= 0 && bufferView < model->bufferViews.size()) {
|
||||||
TINYGLTF_TARGET_ARRAY_BUFFER;
|
model->bufferViews[size_t(bufferView)].target =
|
||||||
|
TINYGLTF_TARGET_ARRAY_BUFFER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5830,13 +5880,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
|||||||
{
|
{
|
||||||
json_const_iterator it;
|
json_const_iterator it;
|
||||||
if (FindMember(o, "extensions", it)) {
|
if (FindMember(o, "extensions", it)) {
|
||||||
model->extensions_json_string = JsonToString(GetValue(it));
|
scene.extensions_json_string = JsonToString(GetValue(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
json_const_iterator it;
|
json_const_iterator it;
|
||||||
if (FindMember(o, "extras", it)) {
|
if (FindMember(o, "extras", it)) {
|
||||||
model->extras_json_string = JsonToString(GetValue(it));
|
scene.extras_json_string = JsonToString(GetValue(it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6216,44 +6266,125 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
|
|||||||
|
|
||||||
unsigned int version; // 4 bytes
|
unsigned int version; // 4 bytes
|
||||||
unsigned int length; // 4 bytes
|
unsigned int length; // 4 bytes
|
||||||
unsigned int model_length; // 4 bytes
|
unsigned int chunk0_length; // 4 bytes
|
||||||
unsigned int model_format; // 4 bytes;
|
unsigned int chunk0_format; // 4 bytes;
|
||||||
|
|
||||||
// @todo { Endian swap for big endian machine. }
|
|
||||||
memcpy(&version, bytes + 4, 4);
|
memcpy(&version, bytes + 4, 4);
|
||||||
swap4(&version);
|
swap4(&version);
|
||||||
memcpy(&length, bytes + 8, 4);
|
memcpy(&length, bytes + 8, 4);
|
||||||
swap4(&length);
|
swap4(&length);
|
||||||
memcpy(&model_length, bytes + 12, 4);
|
memcpy(&chunk0_length, bytes + 12, 4); // JSON data length
|
||||||
swap4(&model_length);
|
swap4(&chunk0_length);
|
||||||
memcpy(&model_format, bytes + 16, 4);
|
memcpy(&chunk0_format, bytes + 16, 4);
|
||||||
swap4(&model_format);
|
swap4(&chunk0_format);
|
||||||
|
|
||||||
|
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-gltf-layout
|
||||||
|
//
|
||||||
// In case the Bin buffer is not present, the size is exactly 20 + size of
|
// In case the Bin buffer is not present, the size is exactly 20 + size of
|
||||||
// JSON contents,
|
// JSON contents,
|
||||||
// so use "greater than" operator.
|
// so use "greater than" operator.
|
||||||
if ((20 + model_length > size) || (model_length < 1) || (length > size) ||
|
//
|
||||||
(20 + model_length > length) ||
|
// https://github.com/syoyo/tinygltf/issues/372
|
||||||
(model_format != 0x4E4F534A)) { // 0x4E4F534A = JSON format.
|
// Use 64bit uint to avoid integer overflow.
|
||||||
|
uint64_t header_and_json_size = 20ull + uint64_t(chunk0_length);
|
||||||
|
|
||||||
|
if (header_and_json_size > std::numeric_limits<uint32_t>::max()) {
|
||||||
|
// Do not allow 4GB or more GLB data.
|
||||||
|
(*err) = "Invalid glTF binary. GLB data exceeds 4GB.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((header_and_json_size > uint64_t(size)) || (chunk0_length < 1) || (length > size) ||
|
||||||
|
(header_and_json_size > uint64_t(length)) ||
|
||||||
|
(chunk0_format != 0x4E4F534A)) { // 0x4E4F534A = JSON format.
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = "Invalid glTF binary.";
|
(*err) = "Invalid glTF binary.";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Padding check
|
||||||
|
// The start and the end of each chunk must be aligned to a 4-byte boundary.
|
||||||
|
// No padding check for chunk0 start since its 4byte-boundary is ensured.
|
||||||
|
if ((header_and_json_size % 4) != 0) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "JSON Chunk end does not aligned to a 4-byte boundary.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "header_and_json_size = " << header_and_json_size << "\n";
|
||||||
|
//std::cout << "length = " << length << "\n";
|
||||||
|
|
||||||
|
// Chunk1(BIN) data
|
||||||
|
// The spec says: When the binary buffer is empty or when it is stored by other means, this chunk SHOULD be omitted.
|
||||||
|
// So when header + JSON data == binary size, Chunk1 is omitted.
|
||||||
|
if (header_and_json_size == uint64_t(length)) {
|
||||||
|
|
||||||
|
bin_data_ = nullptr;
|
||||||
|
bin_size_ = 0;
|
||||||
|
} else {
|
||||||
|
// Read Chunk1 info(BIN data)
|
||||||
|
// At least Chunk1 should have 12 bytes(8 bytes(header) + 4 bytes(bin payload could be 1~3 bytes, but need to be aliged to 4 bytes)
|
||||||
|
if ((header_and_json_size + 12ull) > uint64_t(length)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "Insufficient storage space for Chunk1(BIN data). At least Chunk1 Must have 4 bytes or more bytes, but got " + std::to_string((header_and_json_size + 12ull) - uint64_t(length)) + ".\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int chunk1_length; // 4 bytes
|
||||||
|
unsigned int chunk1_format; // 4 bytes;
|
||||||
|
memcpy(&chunk1_length, bytes + header_and_json_size, 4); // JSON data length
|
||||||
|
swap4(&chunk1_length);
|
||||||
|
memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4);
|
||||||
|
swap4(&chunk1_format);
|
||||||
|
|
||||||
|
//std::cout << "chunk1_length = " << chunk1_length << "\n";
|
||||||
|
|
||||||
|
if (chunk1_length < 4) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "Insufficient Chunk1(BIN) data size.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((chunk1_length % 4) != 0) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "BIN Chunk end does not aligned to a 4-byte boundary.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "BIN Chunk data length exceeds the GLB size.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk1_format != 0x004e4942) {
|
||||||
|
if (err) {
|
||||||
|
(*err) = "Invlid type for chunk1 data.";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "chunk1_length = " << chunk1_length << "\n";
|
||||||
|
|
||||||
|
bin_data_ = bytes + header_and_json_size +
|
||||||
|
8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format)
|
||||||
|
|
||||||
|
bin_size_ = size_t(chunk1_length);
|
||||||
|
}
|
||||||
|
|
||||||
// Extract JSON string.
|
// Extract JSON string.
|
||||||
std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
|
std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
|
||||||
model_length);
|
chunk0_length);
|
||||||
|
|
||||||
is_binary_ = true;
|
is_binary_ = true;
|
||||||
bin_data_ = bytes + 20 + model_length +
|
|
||||||
8; // 4 bytes (buffer_length) + 4 bytes(buffer_format)
|
|
||||||
bin_size_ =
|
|
||||||
length - (20 + model_length); // extract header + JSON scene data.
|
|
||||||
|
|
||||||
bool ret = LoadFromString(model, err, warn,
|
bool ret = LoadFromString(model, err, warn,
|
||||||
reinterpret_cast<const char *>(&bytes[20]),
|
reinterpret_cast<const char *>(&bytes[20]),
|
||||||
model_length, base_dir, check_sections);
|
chunk0_length, base_dir, check_sections);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -6684,6 +6815,27 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) {
|
|||||||
if (accessor.extras.Type() != NULL_TYPE) {
|
if (accessor.extras.Type() != NULL_TYPE) {
|
||||||
SerializeValue("extras", accessor.extras, o);
|
SerializeValue("extras", accessor.extras, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sparse
|
||||||
|
if (accessor.sparse.isSparse)
|
||||||
|
{
|
||||||
|
json sparse;
|
||||||
|
SerializeNumberProperty<int>("count", accessor.sparse.count, sparse);
|
||||||
|
{
|
||||||
|
json indices;
|
||||||
|
SerializeNumberProperty<int>("bufferView", accessor.sparse.indices.bufferView, indices);
|
||||||
|
SerializeNumberProperty<int>("byteOffset", accessor.sparse.indices.byteOffset, indices);
|
||||||
|
SerializeNumberProperty<int>("componentType", accessor.sparse.indices.componentType, indices);
|
||||||
|
JsonAddMember(sparse, "indices", std::move(indices));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json values;
|
||||||
|
SerializeNumberProperty<int>("bufferView", accessor.sparse.values.bufferView, values);
|
||||||
|
SerializeNumberProperty<int>("byteOffset", accessor.sparse.values.byteOffset, values);
|
||||||
|
JsonAddMember(sparse, "values", std::move(values));
|
||||||
|
}
|
||||||
|
JsonAddMember(o, "sparse", std::move(sparse));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
|
||||||
@@ -7166,7 +7318,7 @@ static void SerializeGltfSampler(Sampler &sampler, json &o) {
|
|||||||
if (sampler.minFilter != -1) {
|
if (sampler.minFilter != -1) {
|
||||||
SerializeNumberProperty("minFilter", sampler.minFilter, o);
|
SerializeNumberProperty("minFilter", sampler.minFilter, o);
|
||||||
}
|
}
|
||||||
//SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
// SerializeNumberProperty("wrapR", sampler.wrapR, o);
|
||||||
SerializeNumberProperty("wrapS", sampler.wrapS, o);
|
SerializeNumberProperty("wrapS", sampler.wrapS, o);
|
||||||
SerializeNumberProperty("wrapT", sampler.wrapT, o);
|
SerializeNumberProperty("wrapT", sampler.wrapT, o);
|
||||||
|
|
||||||
@@ -7241,11 +7393,17 @@ static void SerializeGltfScene(Scene &scene, json &o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SerializeGltfSkin(Skin &skin, json &o) {
|
static void SerializeGltfSkin(Skin &skin, json &o) {
|
||||||
if (skin.inverseBindMatrices != -1)
|
// required
|
||||||
SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o);
|
|
||||||
|
|
||||||
SerializeNumberArrayProperty<int>("joints", skin.joints, o);
|
SerializeNumberArrayProperty<int>("joints", skin.joints, o);
|
||||||
SerializeNumberProperty("skeleton", skin.skeleton, o);
|
|
||||||
|
if (skin.inverseBindMatrices >= 0) {
|
||||||
|
SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skin.skeleton >= 0) {
|
||||||
|
SerializeNumberProperty("skeleton", skin.skeleton, o);
|
||||||
|
}
|
||||||
|
|
||||||
if (skin.name.size()) {
|
if (skin.name.size()) {
|
||||||
SerializeStringProperty("name", skin.name, o);
|
SerializeStringProperty("name", skin.name, o);
|
||||||
}
|
}
|
||||||
@@ -7514,37 +7672,32 @@ static bool WriteGltfFile(const std::string &output,
|
|||||||
return WriteGltfStream(gltfFile, content);
|
return WriteGltfStream(gltfFile, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBinaryGltfStream(std::ostream &stream,
|
static bool WriteBinaryGltfStream(std::ostream &stream,
|
||||||
const std::string &content,
|
const std::string &content,
|
||||||
const std::vector<unsigned char> &binBuffer) {
|
const std::vector<unsigned char> &binBuffer) {
|
||||||
const std::string header = "glTF";
|
const std::string header = "glTF";
|
||||||
const int version = 2;
|
const int version = 2;
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number
|
const uint32_t content_size = uint32_t(content.size());
|
||||||
auto roundUp = [](uint32_t numToRound, uint32_t multiple) {
|
const uint32_t binBuffer_size = uint32_t(binBuffer.size());
|
||||||
if (multiple == 0) return numToRound;
|
// determine number of padding bytes required to ensure 4 byte alignment
|
||||||
|
const uint32_t content_padding_size =
|
||||||
uint32_t remainder = numToRound % multiple;
|
content_size % 4 == 0 ? 0 : 4 - content_size % 4;
|
||||||
if (remainder == 0) return numToRound;
|
const uint32_t bin_padding_size =
|
||||||
|
binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4;
|
||||||
return numToRound + multiple - remainder;
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint32_t padding_size =
|
|
||||||
roundUp(uint32_t(content.size()), 4) - uint32_t(content.size());
|
|
||||||
|
|
||||||
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
|
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
|
||||||
// Chunk data must be located at 4-byte boundary.
|
// Chunk data must be located at 4-byte boundary, which may require padding
|
||||||
const uint32_t length =
|
const uint32_t length =
|
||||||
12 + 8 + roundUp(uint32_t(content.size()), 4) +
|
12 + 8 + content_size + content_padding_size +
|
||||||
(binBuffer.size() ? (8 + roundUp(uint32_t(binBuffer.size()), 4)) : 0);
|
(binBuffer_size ? (8 + binBuffer_size + bin_padding_size) : 0);
|
||||||
|
|
||||||
stream.write(header.c_str(), std::streamsize(header.size()));
|
stream.write(header.c_str(), std::streamsize(header.size()));
|
||||||
stream.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
stream.write(reinterpret_cast<const char *>(&version), sizeof(version));
|
||||||
stream.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
stream.write(reinterpret_cast<const char *>(&length), sizeof(length));
|
||||||
|
|
||||||
// JSON chunk info, then JSON data
|
// JSON chunk info, then JSON data
|
||||||
const uint32_t model_length = uint32_t(content.size()) + padding_size;
|
const uint32_t model_length = uint32_t(content.size()) + content_padding_size;
|
||||||
const uint32_t model_format = 0x4E4F534A;
|
const uint32_t model_format = 0x4E4F534A;
|
||||||
stream.write(reinterpret_cast<const char *>(&model_length),
|
stream.write(reinterpret_cast<const char *>(&model_length),
|
||||||
sizeof(model_length));
|
sizeof(model_length));
|
||||||
@@ -7553,13 +7706,11 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|||||||
stream.write(content.c_str(), std::streamsize(content.size()));
|
stream.write(content.c_str(), std::streamsize(content.size()));
|
||||||
|
|
||||||
// Chunk must be multiplies of 4, so pad with spaces
|
// Chunk must be multiplies of 4, so pad with spaces
|
||||||
if (padding_size > 0) {
|
if (content_padding_size > 0) {
|
||||||
const std::string padding = std::string(size_t(padding_size), ' ');
|
const std::string padding = std::string(size_t(content_padding_size), ' ');
|
||||||
stream.write(padding.c_str(), std::streamsize(padding.size()));
|
stream.write(padding.c_str(), std::streamsize(padding.size()));
|
||||||
}
|
}
|
||||||
if (binBuffer.size() > 0) {
|
if (binBuffer.size() > 0) {
|
||||||
const uint32_t bin_padding_size =
|
|
||||||
roundUp(uint32_t(binBuffer.size()), 4) - uint32_t(binBuffer.size());
|
|
||||||
// BIN chunk info, then BIN data
|
// BIN chunk info, then BIN data
|
||||||
const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size;
|
const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size;
|
||||||
const uint32_t bin_format = 0x004e4942;
|
const uint32_t bin_format = 0x004e4942;
|
||||||
@@ -7577,9 +7728,12 @@ static void WriteBinaryGltfStream(std::ostream &stream,
|
|||||||
std::streamsize(padding.size()));
|
std::streamsize(padding.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Check error on stream.write
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBinaryGltfFile(const std::string &output,
|
static bool WriteBinaryGltfFile(const std::string &output,
|
||||||
const std::string &content,
|
const std::string &content,
|
||||||
const std::vector<unsigned char> &binBuffer) {
|
const std::vector<unsigned char> &binBuffer) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -7597,7 +7751,7 @@ static void WriteBinaryGltfFile(const std::string &output,
|
|||||||
#else
|
#else
|
||||||
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
std::ofstream gltfFile(output.c_str(), std::ios::binary);
|
||||||
#endif
|
#endif
|
||||||
WriteBinaryGltfStream(gltfFile, content, binBuffer);
|
return WriteBinaryGltfStream(gltfFile, content, binBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
||||||
@@ -7636,7 +7790,7 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
// UpdateImageObject need baseDir but only uses it if embeddedImages is
|
||||||
// enabled, since we won't write separate images when writing to a stream
|
// enabled, since we won't write separate images when writing to a stream
|
||||||
// we
|
// we
|
||||||
UpdateImageObject(model->images[i], dummystring, int(i), false,
|
UpdateImageObject(model->images[i], dummystring, int(i), true,
|
||||||
&this->WriteImageData, this->write_image_user_data_);
|
&this->WriteImageData, this->write_image_user_data_);
|
||||||
SerializeGltfImage(model->images[i], image);
|
SerializeGltfImage(model->images[i], image);
|
||||||
JsonPushBack(images, std::move(image));
|
JsonPushBack(images, std::move(image));
|
||||||
@@ -7645,12 +7799,11 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (writeBinary) {
|
if (writeBinary) {
|
||||||
WriteBinaryGltfStream(stream, JsonToString(output), binBuffer);
|
return WriteBinaryGltfStream(stream, JsonToString(output), binBuffer);
|
||||||
} else {
|
} else {
|
||||||
WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
|
return WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
||||||
@@ -7735,12 +7888,11 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (writeBinary) {
|
if (writeBinary) {
|
||||||
WriteBinaryGltfFile(filename, JsonToString(output), binBuffer);
|
return WriteBinaryGltfFile(filename, JsonToString(output), binBuffer);
|
||||||
} else {
|
} else {
|
||||||
WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
|
return WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tinygltf
|
} // namespace tinygltf
|
||||||
|
|||||||
Reference in New Issue
Block a user