Merge branch 'separate-serializer' into sajson
diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
new file mode 100644
index 0000000..9424b6d
--- /dev/null
+++ b/.github/workflows/c-cpp.yml
@@ -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
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e7864e5..30cc854 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,18 +4,24 @@
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
loader_example.cc
)
+endif (TINYGLTF_BUILD_LOADER_EXAMPLE)
+if (TINYGLTF_BUILD_GL_EXAMPLES)
ADD_SUBDIRECTORY ( examples/gltfutil )
ADD_SUBDIRECTORY ( examples/glview )
- ADD_SUBDIRECTORY ( examples/validator )
-endif (TINYGLTF_BUILD_EXAMPLES)
+endif (TINYGLTF_BUILD_GL_EXAMPLES)
+if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
+ ADD_SUBDIRECTORY ( examples/validator )
+endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
#
# TinuGLTF is a header-only library, so no library build. just install header files.
#
diff --git a/README.md b/README.md
index 2d9143d..0b9d4c5 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@
[](https://ci.appveyor.com/project/syoyo/tinygltf)
+
+
## Features
* Written in portable C++. C++-11 with STL dependency only.
@@ -83,6 +85,7 @@
* [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf.
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
+* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11
* Your projects here! (Please send PR)
## TODOs
@@ -150,6 +153,7 @@
## Compile options
+* `TINYGLTF_ENABLE_SERIALIZER` : Enable glTF serialization feature.
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
* `TINYGLTF_NO_STB_IMAGE_WRITE` : Do not write images with stb_image_write. Instead use `TinyGLTF::SetImageWriter(WriteimageDataFunction WriteImageData, void *user_data)` to set a callback for writing images.
diff --git a/models/Extensions-overwrite-issue261/issue-261.bin b/models/Extensions-overwrite-issue261/issue-261.bin
new file mode 100644
index 0000000..60ed1b7
--- /dev/null
+++ b/models/Extensions-overwrite-issue261/issue-261.bin
Binary files differ
diff --git a/models/Extensions-overwrite-issue261/issue-261.gltf b/models/Extensions-overwrite-issue261/issue-261.gltf
new file mode 100644
index 0000000..7dd85e2
--- /dev/null
+++ b/models/Extensions-overwrite-issue261/issue-261.gltf
@@ -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
+ ]
+ }
+ ]
+}
diff --git a/tests/tester.cc b/tests/tester.cc
index c6d31b0..012b54d 100644
--- a/tests/tester.cc
+++ b/tests/tester.cc
@@ -93,6 +93,59 @@
}
+TEST_CASE("extension-overwrite", "[issue-261]") {
+
+ tinygltf::Model model;
+ tinygltf::TinyGLTF ctx;
+ std::string err;
+ std::string warn;
+
+ bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/Extensions-overwrite-issue261/issue-261.gltf");
+ if (!err.empty()) {
+ std::cerr << err << std::endl;
+ }
+ REQUIRE(true == ret);
+
+ REQUIRE(model.extensionsUsed.size() == 3);
+ {
+ bool has_ext_lights = false;
+ has_ext_lights |= (model.extensionsUsed[0].compare("KHR_lights_punctual") == 0);
+ has_ext_lights |= (model.extensionsUsed[1].compare("KHR_lights_punctual") == 0);
+ has_ext_lights |= (model.extensionsUsed[2].compare("KHR_lights_punctual") == 0);
+
+ REQUIRE(true == has_ext_lights);
+ }
+
+ {
+ REQUIRE(model.extensions.size() == 2);
+ REQUIRE(model.extensions.count("NV_MDL"));
+ REQUIRE(model.extensions.count("KHR_lights_punctual"));
+ }
+
+ // TODO(syoyo): create temp directory.
+ {
+ ret = ctx.WriteGltfSceneToFile(&model, "issue-261.gltf", true, true);
+ REQUIRE(true == ret);
+
+ tinygltf::Model m;
+
+ // read back serialized glTF
+ bool ret = ctx.LoadASCIIFromFile(&m, &err, &warn, "issue-261.gltf");
+ if (!err.empty()) {
+ std::cerr << err << std::endl;
+ }
+ REQUIRE(true == ret);
+
+ REQUIRE(m.extensionsUsed.size() == 3);
+
+ REQUIRE(m.extensions.size() == 2);
+ REQUIRE(m.extensions.count("NV_MDL"));
+ REQUIRE(m.extensions.count("KHR_lights_punctual"));
+
+ }
+
+}
+
TEST_CASE("invalid-primitive-indices", "[bounds-checking]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
@@ -359,3 +412,19 @@
REQUIRE(true == ret);
}
+#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
diff --git a/tiny_gltf.h b/tiny_gltf.h
index 262dbd3..d7592e1 100644
--- a/tiny_gltf.h
+++ b/tiny_gltf.h
@@ -27,6 +27,7 @@
// Version:
// - v2.4.3 Experimental sajson(lightweight JSON parser) backend support.
+// Introduce TINYGLTF_ENABLE_SERIALIZER.
// - v2.4.2 Decode percent-encoded URI.
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
// `extras` property.
@@ -54,6 +55,7 @@
#include <array>
#include <cassert>
+#include <cmath> // std::fabs
#include <cstdint>
#include <cstdlib>
#include <cstring>
@@ -61,7 +63,6 @@
#include <map>
#include <string>
#include <vector>
-#include <cmath> // std::fabs
#ifndef TINYGLTF_USE_CPP14
#include <functional>
@@ -325,7 +326,8 @@
}
// 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) {
return int(real_value_);
} else {
@@ -1116,9 +1118,9 @@
struct Light {
std::string name;
std::vector<double> color;
- double intensity;
+ double intensity{1.0};
std::string type;
- double range;
+ double range{0.0}; // 0.0 = inifinite
SpotLight spot;
Light() : intensity(1.0), range(0.0) {}
@@ -1250,7 +1252,13 @@
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,
const std::string &filepath, void *);
@@ -1318,6 +1326,8 @@
const std::string &base_dir = "",
unsigned int check_sections = REQUIRE_VERSION);
+#if defined(TINYGLTF_ENABLE_SERIALIZER)
+
///
/// Write glTF to stream, buffers and images will be embeded
///
@@ -1331,16 +1341,22 @@
bool embedImages, bool embedBuffers,
bool prettyPrint, bool writeBinary);
+#endif
+
///
/// Set callback to use for loading image data
///
void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
+#if defined(TINYGLTF_ENABLE_SERIALIZER)
+
///
/// Set callback to use for writing image data
///
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
+#endif
+
///
/// Set callbacks to use for filesystem (fs) access and their user data
///
@@ -2420,11 +2436,15 @@
}
#endif
+#if defined(TINYGLTF_ENABLE_SERIALIZER)
+
void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) {
WriteImageData = func;
write_image_user_data_ = user_data;
}
+#endif
+
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
static void WriteToMemory_stbi(void *context, void *data, int size) {
std::vector<unsigned char> *buffer =
@@ -2516,6 +2536,15 @@
(int)wstr.size());
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
#ifndef TINYGLTF_NO_FS
@@ -2567,15 +2596,16 @@
std::string ExpandFilePath(const std::string &filepath, void *) {
#ifdef _WIN32
- DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0);
- char *str = new char[len];
- ExpandEnvironmentStringsA(filepath.c_str(), str, len);
+ // Assume input `filepath` is encoded in UTF-8
+ std::wstring wfilepath = UTF8ToWchar(filepath);
+ 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
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
@@ -2651,9 +2681,11 @@
_wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
__gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
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);
-#else // clang?
+#else
+ // Unknown compiler/runtime
std::ifstream f(filepath.c_str(), std::ifstream::binary);
#endif
#else
@@ -2695,12 +2727,10 @@
const std::vector<unsigned char> &contents, void *) {
#ifdef _WIN32
#if defined(__GLIBCXX__) // mingw
- int file_descriptor =
- _wopen(UTF8ToWchar(filepath).c_str(), _O_CREAT | _O_WRONLY |
- _O_TRUNC | _O_BINARY);
- __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor,
- std::ios_base::out |
- std::ios_base::binary);
+ int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
+ _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
+ __gnu_cxx::stdio_filebuf<char> wfile_buf(
+ file_descriptor, std::ios_base::out | std::ios_base::binary);
std::ostream f(&wfile_buf);
#elif defined(_MSC_VER)
std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
@@ -2755,10 +2785,9 @@
if (image.uri.size()) {
filename = GetBaseFilename(image.uri);
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.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()) {
ext = MimeToExt(image.mimeType);
// Otherwise use name as filename
@@ -2909,7 +2938,7 @@
return false;
#elif defined(TINYGLTF_USE_SAJSON)
auto type = o.get_type();
-
+
if (type == sajson::TYPE_INTEGER) {
val = static_cast<int>(o.get_number_value());
return true;
@@ -2950,7 +2979,7 @@
return false;
#elif defined(TINYGLTF_USE_SAJSON)
auto type = o.get_type();
-
+
if ((type == sajson::TYPE_DOUBLE) ||
(type == sajson::TYPE_INTEGER)) {
val = static_cast<double>(o.get_number_value());
@@ -2978,7 +3007,7 @@
return false;
#elif defined(TINYGLTF_USE_SAJSON)
auto type = o.get_type();
-
+
if (type == sajson::TYPE_STRING) {
val = o.as_string();
return true;
@@ -4944,13 +4973,13 @@
}
return false;
}
- ParseExtensionsProperty(&channel->target_extensions, err, target_object);
- if (store_original_json_for_extras_and_extensions) {
+ 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;
@@ -5761,9 +5790,11 @@
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
}
- for(auto &target : primitive.targets) {
- for(auto &attribute : target) {
- model->bufferViews[size_t(model->accessors[size_t(attribute.second)].bufferView)]
+ for (auto &target : primitive.targets) {
+ for (auto &attribute : target) {
+ model
+ ->bufferViews[size_t(
+ model->accessors[size_t(attribute.second)].bufferView)]
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
}
}
@@ -6273,6 +6304,8 @@
return ret;
}
+#if defined(TINYGLTF_ENABLE_SERIALIZER)
+
///////////////////////
// GLTF Serialization
///////////////////////
@@ -6349,6 +6382,13 @@
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>
static void SerializeNumberArrayProperty(const std::string &key,
const std::vector<T> &value,
@@ -6499,12 +6539,10 @@
const std::string &binFilename) {
#ifdef _WIN32
#if defined(__GLIBCXX__) // mingw
- int file_descriptor =
- _wopen(UTF8ToWchar(binFilename).c_str(), _O_CREAT | _O_WRONLY |
- _O_TRUNC | _O_BINARY);
- __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor,
- std::ios_base::out |
- std::ios_base::binary);
+ int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(),
+ _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
+ __gnu_cxx::stdio_filebuf<char> wfile_buf(
+ file_descriptor, std::ios_base::out | std::ios_base::binary);
std::ostream output(&wfile_buf);
if (!wfile_buf.is_open()) return false;
#elif defined(_MSC_VER)
@@ -6639,7 +6677,7 @@
SerializeNumberProperty("node", channel.target_node, target);
SerializeStringProperty("path", channel.target_path, target);
- SerializeExtensionMap(channel.target_extensions, target);
+ SerializeExtensionMap(channel.target_extensions, target);
JsonAddMember(o, "target", std::move(target));
}
@@ -7046,7 +7084,9 @@
static void SerializeGltfLight(Light &light, json &o) {
if (!light.name.empty()) SerializeStringProperty("name", light.name, 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);
SerializeStringProperty("type", light.type, o);
if (light.type == "spot") {
@@ -7160,6 +7200,11 @@
} else {
// ???
}
+
+ if (camera.extras.Type() != NULL_TYPE) {
+ SerializeValue("extras", camera.extras, o);
+ }
+ SerializeExtensionMap(camera.extensions, o);
}
static void SerializeGltfScene(Scene &scene, json &o) {
@@ -7238,7 +7283,7 @@
JsonAddMember(o, "asset", std::move(asset));
// BUFFERVIEWS
- if(model->bufferViews.size()) {
+ if (model->bufferViews.size()) {
json bufferViews;
JsonReserveArray(bufferViews, model->bufferViews.size());
for (unsigned int i = 0; i < model->bufferViews.size(); ++i) {
@@ -7249,11 +7294,6 @@
JsonAddMember(o, "bufferViews", std::move(bufferViews));
}
- // Extensions used
- if (model->extensionsUsed.size()) {
- SerializeStringArrayProperty("extensionsUsed", model->extensionsUsed, o);
- }
-
// Extensions required
if (model->extensionsRequired.size()) {
SerializeStringArrayProperty("extensionsRequired",
@@ -7364,7 +7404,9 @@
// EXTENSIONS
SerializeExtensionMap(model->extensions, o);
- // LIGHTS as KHR_lights_cmn
+ auto extensionsUsed = model->extensionsUsed;
+
+ // LIGHTS as KHR_lights_punctual
if (model->lights.size()) {
json lights;
JsonReserveArray(lights, model->lights.size());
@@ -7379,7 +7421,7 @@
{
json_const_iterator it;
- if (!FindMember(o, "extensions", it)) {
+ if (FindMember(o, "extensions", it)) {
JsonAssign(ext_j, GetValue(it));
}
}
@@ -7387,6 +7429,23 @@
JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn));
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
@@ -7406,12 +7465,10 @@
#if defined(_MSC_VER)
std::ofstream gltfFile(UTF8ToWchar(output).c_str());
#elif defined(__GLIBCXX__)
- int file_descriptor =
- _wopen(UTF8ToWchar(output).c_str(), _O_CREAT | _O_WRONLY |
- _O_TRUNC | _O_BINARY);
- __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor,
- std::ios_base::out |
- std::ios_base::binary);
+ int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
+ _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
+ __gnu_cxx::stdio_filebuf<char> wfile_buf(
+ file_descriptor, std::ios_base::out | std::ios_base::binary);
std::ostream gltfFile(&wfile_buf);
if (!wfile_buf.is_open()) return false;
#else
@@ -7497,12 +7554,10 @@
#if defined(_MSC_VER)
std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary);
#elif defined(__GLIBCXX__)
- int file_descriptor =
- _wopen(UTF8ToWchar(output).c_str(), _O_CREAT | _O_WRONLY |
- _O_TRUNC | _O_BINARY);
- __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor,
- std::ios_base::out |
- std::ios_base::binary);
+ int file_descriptor = _wopen(UTF8ToWchar(output).c_str(),
+ _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
+ __gnu_cxx::stdio_filebuf<char> wfile_buf(
+ file_descriptor, std::ios_base::out | std::ios_base::binary);
std::ostream gltfFile(&wfile_buf);
#else
std::ofstream gltfFile(output.c_str(), std::ios::binary);
@@ -7523,13 +7578,13 @@
// BUFFERS
std::vector<unsigned char> binBuffer;
- if(model->buffers.size()) {
+ if (model->buffers.size()) {
json buffers;
JsonReserveArray(buffers, model->buffers.size());
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
json buffer;
- if (writeBinary && i==0 && model->buffers[i].uri.empty()){
- SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
+ if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
+ SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
} else {
SerializeGltfBuffer(model->buffers[i], buffer);
}
@@ -7546,10 +7601,11 @@
json image;
std::string dummystring = "";
- // UpdateImageObject need baseDir but only uses it if embeddedImages is
- // enabled, since we won't write separate images when writing to a stream we
- UpdateImageObject(model->images[i], dummystring, int(i), false,
- &this->WriteImageData, this->write_image_user_data_);
+ // UpdateImageObject need baseDir but only uses it if embeddedImages is
+ // enabled, since we won't write separate images when writing to a stream
+ // we
+ UpdateImageObject(model->images[i], dummystring, int(i), false,
+ &this->WriteImageData, this->write_image_user_data_);
SerializeGltfImage(model->images[i], image);
JsonPushBack(images, std::move(image));
}
@@ -7594,14 +7650,15 @@
JsonReserveArray(buffers, model->buffers.size());
for (unsigned int i = 0; i < model->buffers.size(); ++i) {
json buffer;
- if (writeBinary && i==0 && model->buffers[i].uri.empty()){
- SerializeGltfBufferBin(model->buffers[i], buffer,binBuffer);
+ if (writeBinary && i == 0 && model->buffers[i].uri.empty()) {
+ SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer);
} else if (embedBuffers) {
SerializeGltfBuffer(model->buffers[i], buffer);
} else {
std::string binSavePath;
std::string binUri;
- if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
+ if (!model->buffers[i].uri.empty() &&
+ !IsDataURI(model->buffers[i].uri)) {
binUri = model->buffers[i].uri;
} else {
binUri = defaultBinFilename + defaultBinFileExt;
@@ -7627,7 +7684,7 @@
}
JsonPushBack(buffers, std::move(buffer));
}
- JsonAddMember(output, "buffers", std::move(buffers));
+ JsonAddMember(output, "buffers", std::move(buffers));
}
// IMAGES
@@ -7654,6 +7711,8 @@
return true;
}
+#endif // TINYGLTF_ENABLE_SERIALIZER
+
} // namespace tinygltf
#ifdef __clang__