New Upstream Release - tinygltf
Ready changes
Summary
Merged new upstream version: 2.8.2+dfsg (was: 2.7.0+dfsg).
Diff
diff --git a/README.md b/README.md
index b3c2ed8..bb88fb5 100644
--- a/README.md
+++ b/README.md
@@ -2,20 +2,22 @@
`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
-Currently TinyGLTF is stable and maintainance mode. No drastic changes and feature additions planned.
+Currently TinyGLTF is stable and maintenance mode. No drastic changes and feature additions planned.
+ - v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397
+ - v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393
- 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.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.1.0 release(Draco support)
+ - v2.1.0 release(Draco decoding support)
- v2.0.0 release(22 Aug, 2018)!
### Branches
diff --git a/debian/changelog b/debian/changelog
index a2d29fc..99600b5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+tinygltf (2.8.2+dfsg-1) UNRELEASED; urgency=low
+
+ * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk> Wed, 08 Feb 2023 00:00:47 -0000
+
tinygltf (2.7.0+dfsg-2) unstable; urgency=medium
* Upload to unstable.
diff --git a/debian/patches/0001-Fix-build-system.patch b/debian/patches/0001-Fix-build-system.patch
index 81526e1..fecc3f8 100644
--- a/debian/patches/0001-Fix-build-system.patch
+++ b/debian/patches/0001-Fix-build-system.patch
@@ -10,10 +10,10 @@ Forwarded: not-needed
3 files changed, 53 insertions(+), 46 deletions(-)
create mode 100644 tiny_gltf.cpp
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 0df1614..4494276 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
+Index: tinygltf.git/CMakeLists.txt
+===================================================================
+--- tinygltf.git.orig/CMakeLists.txt
++++ tinygltf.git/CMakeLists.txt
@@ -1,11 +1,13 @@
cmake_minimum_required(VERSION 3.6)
@@ -37,41 +37,13 @@ index 0df1614..4494276 100644
-if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
- ADD_SUBDIRECTORY ( examples/build-gltf )
-endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
-+add_library(${PROJECT_NAME} tiny_gltf.h tiny_gltf.cpp)
-+target_include_directories(${PROJECT_NAME}
-+ PUBLIC
-+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
-+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-+ PRIVATE
-+ ${stb_INCLUDE_DIRS}
-+)
-+target_link_libraries(${PROJECT_NAME} PRIVATE
-+ ${stb_LIBRARY}
-+ nlohmann_json::nlohmann_json
-+)
-+set_target_properties(${PROJECT_NAME} PROPERTIES
-+ OUTPUT_NAME "tinygltf"
-+ VERSION ${PROJECT_VERSION}
-+ SOVERSION 2d
-+)
-+add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
-
+-
-#
-# for add_subdirectory and standalone build
-#
-if (TINYGLTF_HEADER_ONLY)
- add_library(tinygltf INTERFACE)
-+install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
-+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-+)
-+export(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::)
-+install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::
-+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
-+)
-+install(FILES tiny_gltf.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
-
+-
- target_include_directories(tinygltf
- INTERFACE
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@@ -107,6 +79,36 @@ index 0df1614..4494276 100644
- )
-
-endif(TINYGLTF_INSTALL)
++add_library(${PROJECT_NAME} tiny_gltf.h tiny_gltf.cpp)
++target_include_directories(${PROJECT_NAME}
++ PUBLIC
++ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
++ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
++ PRIVATE
++ ${stb_INCLUDE_DIRS}
++)
++target_link_libraries(${PROJECT_NAME} PRIVATE
++ ${stb_LIBRARY}
++ nlohmann_json::nlohmann_json
++)
++set_target_properties(${PROJECT_NAME} PROPERTIES
++ OUTPUT_NAME "tinygltf"
++ VERSION ${PROJECT_VERSION}
++ SOVERSION 2d
++)
++add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
++
++install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
++ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
++ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
++)
++export(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::)
++install(EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}::
++ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
++)
++install(FILES tiny_gltf.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
++
+configure_package_config_file(cmake/${PROJECT_NAME}Config.cmake.in ${PROJECT_NAME}Config.cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ NO_CHECK_REQUIRED_COMPONENTS_MACRO
@@ -118,10 +120,10 @@ index 0df1614..4494276 100644
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+)
-diff --git a/cmake/TinyGLTFConfig.cmake.in b/cmake/TinyGLTFConfig.cmake.in
-index fcccacf..89f21e4 100644
---- a/cmake/TinyGLTFConfig.cmake.in
-+++ b/cmake/TinyGLTFConfig.cmake.in
+Index: tinygltf.git/cmake/TinyGLTFConfig.cmake.in
+===================================================================
+--- tinygltf.git.orig/cmake/TinyGLTFConfig.cmake.in
++++ tinygltf.git/cmake/TinyGLTFConfig.cmake.in
@@ -1,3 +1,9 @@
@PACKAGE_INIT@
@@ -133,11 +135,10 @@ index fcccacf..89f21e4 100644
+set(@PROJECT_NAME@_CONFIG ${CMAKE_CURRENT_LIST_FILE})
+find_package_handle_standard_args(@PROJECT_NAME@ CONFIG_MODE)
+
-diff --git a/tiny_gltf.cpp b/tiny_gltf.cpp
-new file mode 100644
-index 0000000..43e41f4
+Index: tinygltf.git/tiny_gltf.cpp
+===================================================================
--- /dev/null
-+++ b/tiny_gltf.cpp
++++ tinygltf.git/tiny_gltf.cpp
@@ -0,0 +1,3 @@
+#define TINYGLTF_IMPLEMENTATION
+#include "tiny_gltf.h"
diff --git a/debian/patches/0002-Fix-third-party-includes.patch b/debian/patches/0002-Fix-third-party-includes.patch
index 52a3b21..b513af2 100644
--- a/debian/patches/0002-Fix-third-party-includes.patch
+++ b/debian/patches/0002-Fix-third-party-includes.patch
@@ -8,10 +8,10 @@ Forwarded: not-needed
tiny_gltf.h | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
-diff --git a/tests/tester.cc b/tests/tester.cc
-index b43cf4c..f40645a 100644
---- a/tests/tester.cc
-+++ b/tests/tester.cc
+Index: tinygltf.git/tests/tester.cc
+===================================================================
+--- tinygltf.git.orig/tests/tester.cc
++++ tinygltf.git/tests/tester.cc
@@ -4,7 +4,7 @@
#include "tiny_gltf.h"
@@ -21,11 +21,11 @@ index b43cf4c..f40645a 100644
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
-diff --git a/tiny_gltf.h b/tiny_gltf.h
-index b83daa1..b22c6af 100644
---- a/tiny_gltf.h
-+++ b/tiny_gltf.h
-@@ -1568,7 +1568,7 @@ class TinyGLTF {
+Index: tinygltf.git/tiny_gltf.h
+===================================================================
+--- tinygltf.git.orig/tiny_gltf.h
++++ tinygltf.git/tiny_gltf.h
+@@ -1620,7 +1620,7 @@ class TinyGLTF {
#ifndef TINYGLTF_NO_INCLUDE_JSON
#ifndef TINYGLTF_USE_RAPIDJSON
@@ -34,7 +34,7 @@ index b83daa1..b22c6af 100644
#else
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
#include "document.h"
-@@ -1587,13 +1587,13 @@ class TinyGLTF {
+@@ -1639,13 +1639,13 @@ class TinyGLTF {
#ifndef TINYGLTF_NO_STB_IMAGE
#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE
diff --git a/debian/patches/0003-Integrate-unit-tests-into-CMake-build.patch b/debian/patches/0003-Integrate-unit-tests-into-CMake-build.patch
index d14bdec..120a7c4 100644
--- a/debian/patches/0003-Integrate-unit-tests-into-CMake-build.patch
+++ b/debian/patches/0003-Integrate-unit-tests-into-CMake-build.patch
@@ -10,11 +10,11 @@ Forwarded: not-needed
3 files changed, 15 insertions(+), 2 deletions(-)
create mode 100644 tests/CMakeLists.txt
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 4494276..b0ea08d 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -4,6 +4,7 @@ project(TinyGLTF VERSION 2.7.0 LANGUAGES CXX)
+Index: tinygltf.git/CMakeLists.txt
+===================================================================
+--- tinygltf.git.orig/CMakeLists.txt
++++ tinygltf.git/CMakeLists.txt
+@@ -4,6 +4,7 @@ project(TinyGLTF VERSION 2.7.0 LANGUAGES
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
@@ -29,11 +29,10 @@ index 4494276..b0ea08d 100644
+
+add_subdirectory(tests)
+
-diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
-new file mode 100644
-index 0000000..80148fc
+Index: tinygltf.git/tests/CMakeLists.txt
+===================================================================
--- /dev/null
-+++ b/tests/CMakeLists.txt
++++ tinygltf.git/tests/CMakeLists.txt
@@ -0,0 +1,9 @@
+if(BUILD_TESTING)
+ add_executable(tester tester.cc)
@@ -44,10 +43,10 @@ index 0000000..80148fc
+ )
+endif()
+
-diff --git a/tests/tester.cc b/tests/tester.cc
-index f40645a..5edb0af 100644
---- a/tests/tester.cc
-+++ b/tests/tester.cc
+Index: tinygltf.git/tests/tester.cc
+===================================================================
+--- tinygltf.git.orig/tests/tester.cc
++++ tinygltf.git/tests/tester.cc
@@ -1,13 +1,13 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
diff --git a/debian/patches/0004-Add-pkgconfig-file.patch b/debian/patches/0004-Add-pkgconfig-file.patch
index d57da3e..b5f7808 100644
--- a/debian/patches/0004-Add-pkgconfig-file.patch
+++ b/debian/patches/0004-Add-pkgconfig-file.patch
@@ -9,10 +9,10 @@ Forwarded: not-needed
2 files changed, 13 insertions(+)
create mode 100644 tinygltf.pc.in
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index b0ea08d..7fa99c1 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
+Index: tinygltf.git/CMakeLists.txt
+===================================================================
+--- tinygltf.git.orig/CMakeLists.txt
++++ tinygltf.git/CMakeLists.txt
@@ -74,5 +74,8 @@ install(FILES
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
@@ -22,11 +22,10 @@ index b0ea08d..7fa99c1 100644
+
add_subdirectory(tests)
-diff --git a/tinygltf.pc.in b/tinygltf.pc.in
-new file mode 100644
-index 0000000..8e7bae2
+Index: tinygltf.git/tinygltf.pc.in
+===================================================================
--- /dev/null
-+++ b/tinygltf.pc.in
++++ tinygltf.git/tinygltf.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
diff --git a/debian/patches/0005-Hide-nlohmann_json-symbols.patch b/debian/patches/0005-Hide-nlohmann_json-symbols.patch
index b2c71bb..2a83712 100644
--- a/debian/patches/0005-Hide-nlohmann_json-symbols.patch
+++ b/debian/patches/0005-Hide-nlohmann_json-symbols.patch
@@ -6,11 +6,11 @@ Subject: Hide nlohmann_json symbols
tiny_gltf.h | 6 ++++++
1 file changed, 6 insertions(+)
-diff --git a/tiny_gltf.h b/tiny_gltf.h
-index b22c6af..15f63c4 100644
---- a/tiny_gltf.h
-+++ b/tiny_gltf.h
-@@ -1568,7 +1568,13 @@ class TinyGLTF {
+Index: tinygltf.git/tiny_gltf.h
+===================================================================
+--- tinygltf.git.orig/tiny_gltf.h
++++ tinygltf.git/tiny_gltf.h
+@@ -1620,7 +1620,13 @@ class TinyGLTF {
#ifndef TINYGLTF_NO_INCLUDE_JSON
#ifndef TINYGLTF_USE_RAPIDJSON
diff --git a/debian/patches/0006-Big-endian-fix.patch b/debian/patches/0006-Big-endian-fix.patch
index 6c7be84..fa27b5d 100644
--- a/debian/patches/0006-Big-endian-fix.patch
+++ b/debian/patches/0006-Big-endian-fix.patch
@@ -6,11 +6,11 @@ Subject: Big endian fix
tiny_gltf.h | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
-diff --git a/tiny_gltf.h b/tiny_gltf.h
-index 15f63c4..1cc8e36 100644
---- a/tiny_gltf.h
-+++ b/tiny_gltf.h
-@@ -1651,13 +1651,9 @@ class TinyGLTF {
+Index: tinygltf.git/tiny_gltf.h
+===================================================================
+--- tinygltf.git.orig/tiny_gltf.h
++++ tinygltf.git/tiny_gltf.h
+@@ -1703,13 +1703,9 @@ class TinyGLTF {
//#include <wordexp.h>
#endif
@@ -25,7 +25,7 @@ index 15f63c4..1cc8e36 100644
namespace {
#ifdef TINYGLTF_USE_RAPIDJSON
-@@ -7708,7 +7704,8 @@ static bool WriteBinaryGltfStream(std::ostream &stream,
+@@ -7814,7 +7810,8 @@ static bool WriteBinaryGltfStream(std::o
const std::string &content,
const std::vector<unsigned char> &binBuffer) {
const std::string header = "glTF";
@@ -35,7 +35,7 @@ index 15f63c4..1cc8e36 100644
const uint32_t content_size = uint32_t(content.size());
const uint32_t binBuffer_size = uint32_t(binBuffer.size());
-@@ -7720,17 +7717,20 @@ static bool WriteBinaryGltfStream(std::ostream &stream,
+@@ -7826,17 +7823,20 @@ static bool WriteBinaryGltfStream(std::o
// 12 bytes for header, JSON content length, 8 bytes for JSON chunk info.
// Chunk data must be located at 4-byte boundary, which may require padding
@@ -59,7 +59,7 @@ index 15f63c4..1cc8e36 100644
stream.write(reinterpret_cast<const char *>(&model_length),
sizeof(model_length));
stream.write(reinterpret_cast<const char *>(&model_format),
-@@ -7744,8 +7744,10 @@ static bool WriteBinaryGltfStream(std::ostream &stream,
+@@ -7850,8 +7850,10 @@ static bool WriteBinaryGltfStream(std::o
}
if (binBuffer.size() > 0) {
// BIN chunk info, then BIN data
diff --git a/tests/tester.cc b/tests/tester.cc
index b43cf4c..b1be601 100644
--- a/tests/tester.cc
+++ b/tests/tester.cc
@@ -392,27 +392,105 @@ TEST_CASE("pbr-khr-texture-transform", "[material]") {
TEST_CASE("image-uri-spaces", "[issue-236]") {
- tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Test image file with single spaces.
- bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf");
- if (!err.empty()) {
- std::cerr << err << std::endl;
- }
+ {
+ tinygltf::Model model;
+ bool ret = ctx.LoadASCIIFromFile(
+ &model, &err, &warn,
+ "../models/CubeImageUriSpaces/CubeImageUriSpaces.gltf");
+ if (!warn.empty()) {
+ std::cerr << warn << std::endl;
+ }
+ if (!err.empty()) {
+ std::cerr << err << std::endl;
+ }
- REQUIRE(true == ret);
+ REQUIRE(true == ret);
+ REQUIRE(warn.empty());
+ REQUIRE(err.empty());
+ REQUIRE(model.images.size() == 1);
+ REQUIRE(model.images[0].uri.find(' ') != std::string::npos);
+ }
// Test image file with a beginning space, trailing space, and greater than
// one consecutive spaces.
- ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf");
+ tinygltf::Model model;
+ bool ret = ctx.LoadASCIIFromFile(
+ &model, &err, &warn,
+ "../models/CubeImageUriSpaces/CubeImageUriMultipleSpaces.gltf");
+ if (!warn.empty()) {
+ std::cerr << warn << std::endl;
+ }
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
+ REQUIRE(warn.empty());
+ REQUIRE(err.empty());
+ REQUIRE(model.images.size() == 1);
+ REQUIRE(model.images[0].uri.size() > 1);
+ REQUIRE(model.images[0].uri[0] == ' ');
+
+ // Test the URI encoding API by saving and re-load the file, without embedding
+ // the image.
+ // TODO(syoyo): create temp directory.
+ {
+ // Encoder that only replaces spaces with "%20".
+ auto uriencode = [](const std::string &in_uri,
+ const std::string &object_type, std::string *out_uri,
+ void *user_data) -> bool {
+ (void)user_data;
+ bool imageOrBuffer = object_type == "image" || object_type == "buffer";
+ REQUIRE(true == imageOrBuffer);
+ *out_uri = {};
+ for (char c : in_uri) {
+ if (c == ' ')
+ *out_uri += "%20";
+ else
+ *out_uri += c;
+ }
+ return true;
+ };
+
+ // Remove the buffer URI, so a new one is generated based on the gltf
+ // filename and then encoded with the above callback.
+ model.buffers[0].uri.clear();
+
+ tinygltf::URICallbacks uri_cb{uriencode, tinygltf::URIDecode, nullptr};
+ ctx.SetURICallbacks(uri_cb);
+ ret = ctx.WriteGltfSceneToFile(&model, " issue-236.gltf", false, false);
+ REQUIRE(true == ret);
+
+ // read back serialized glTF
+ tinygltf::Model saved;
+ bool ret = ctx.LoadASCIIFromFile(&saved, &err, &warn, " issue-236.gltf");
+ if (!err.empty()) {
+ std::cerr << err << std::endl;
+ }
+ REQUIRE(true == ret);
+ REQUIRE(err.empty());
+ REQUIRE(!warn.empty()); // relative image path won't exist in tests/
+ REQUIRE(saved.images.size() == model.images.size());
+
+ // The image uri in CubeImageUriMultipleSpaces.gltf is not encoded and
+ // should be different after encoding spaces with %20.
+ REQUIRE(model.images[0].uri != saved.images[0].uri);
+
+ // Verify the image path remains the same after uri decoding
+ std::string image_uri, image_uri_saved;
+ (void)tinygltf::URIDecode(model.images[0].uri, &image_uri, nullptr);
+ (void)tinygltf::URIDecode(saved.images[0].uri, &image_uri_saved, nullptr);
+ REQUIRE(image_uri == image_uri_saved);
+
+ // Verify the buffer's generated and encoded URI
+ REQUIRE(saved.buffers.size() == model.buffers.size());
+ REQUIRE(saved.buffers[0].uri == "%20issue-236.bin");
+ }
}
TEST_CASE("serialize-empty-material", "[issue-294]") {
@@ -583,7 +661,11 @@ TEST_CASE("serialize-image-callback", "[issue-394]") {
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
- std::string *out_uri, void *user_pointer) -> bool {
+ const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
+ void *user_pointer) -> bool {
+ (void)basepath;
+ (void)image;
+ (void)uri_cb;
REQUIRE(*filename == "foo");
REQUIRE(embedImages == true);
REQUIRE(user_pointer == (void *)0xba5e1e55);
@@ -593,13 +675,46 @@ TEST_CASE("serialize-image-callback", "[issue-394]") {
tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55);
- ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
+ bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
+ REQUIRE(true == result);
REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() == "bar");
}
+
+TEST_CASE("serialize-image-failure", "[issue-394]") {
+ tinygltf::Model m;
+ tinygltf::Image i;
+ // Set some data so the ImageWriter callback will be called
+ i.image = {255, 255, 255, 255};
+ m.images.push_back(i);
+
+ std::stringstream os;
+
+ auto writer = [](const std::string *basepath, const std::string *filename,
+ const tinygltf::Image *image, bool embedImages,
+ const tinygltf::URICallbacks *uri_cb, std::string *out_uri,
+ void *user_pointer) -> bool {
+ (void)basepath;
+ (void)filename;
+ (void)image;
+ (void)embedImages;
+ (void)uri_cb;
+ (void)out_uri;
+ (void)user_pointer;
+ return false;
+ };
+
+ tinygltf::TinyGLTF ctx;
+ ctx.SetImageWriter(writer, (void *)0xba5e1e55);
+ bool result = ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
+ false);
+
+ REQUIRE(false == result);
+ REQUIRE(os.str().size() == 0);
+}
diff --git a/tiny_gltf.h b/tiny_gltf.h
index b83daa1..b0e2c60 100644
--- a/tiny_gltf.h
+++ b/tiny_gltf.h
@@ -26,6 +26,8 @@
// THE SOFTWARE.
// Version:
+// - v2.8.1 Missed serialization texture sampler name fixed. PR#399.
+// - v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397.
// - v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393.
// - v2.6.3 Fix GLB file with empty BIN chunk was not handled. PR#382 and PR#383.
// - v2.6.2 Fix out-of-bounds access of accessors. PR#379.
@@ -545,9 +547,10 @@ typedef std::map<std::string, Value> ExtensionMap;
struct AnimationChannel {
int sampler; // required
- int target_node; // required (index of the node to target)
- std::string target_path; // required in ["translation", "rotation", "scale",
- // "weights"]
+ int target_node; // optional index of the node to target (alternative
+ // target should be provided by extension)
+ std::string target_path; // required with standard values of ["translation",
+ // "rotation", "scale", "weights"]
Value extras;
ExtensionMap extensions;
ExtensionMap target_extensions;
@@ -1207,6 +1210,39 @@ enum SectionCheck {
REQUIRE_ALL = 0x7f
};
+///
+/// URIEncodeFunction type. Signature for custom URI encoding of external
+/// resources such as .bin and image files. Used by tinygltf to re-encode the
+/// final location of saved files. object_type may be used to encode buffer and
+/// image URIs differently, for example. See
+/// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#uris
+///
+typedef bool (*URIEncodeFunction)(const std::string &in_uri,
+ const std::string &object_type,
+ std::string *out_uri, void *user_data);
+
+///
+/// URIDecodeFunction type. Signature for custom URI decoding of external
+/// resources such as .bin and image files. Used by tinygltf when computing
+/// filenames to write resources.
+///
+typedef bool (*URIDecodeFunction)(const std::string &in_uri,
+ std::string *out_uri, void *user_data);
+
+// Declaration of default uri decode function
+bool URIDecode(const std::string &in_uri, std::string *out_uri,
+ void *user_data);
+
+///
+/// A structure containing URI callbacks and a pointer to their user data.
+///
+struct URICallbacks {
+ URIEncodeFunction encode; // Optional encode method
+ URIDecodeFunction decode; // Required decode method
+
+ void *user_data; // An argument that is passed to all uri callbacks
+};
+
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
@@ -1223,7 +1259,9 @@ typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
typedef bool (*WriteImageDataFunction)(const std::string *basepath,
const std::string *filename,
const Image *image, bool embedImages,
- std::string *out_uri, void *user_pointer);
+ const URICallbacks *uri_cb,
+ std::string *out_uri,
+ void *user_pointer);
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
@@ -1235,8 +1273,8 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
// Declaration of default image writer callback
bool WriteImageData(const std::string *basepath, const std::string *filename,
- const Image *image, bool embedImages, std::string *out_uri,
- void *);
+ const Image *image, bool embedImages,
+ const URICallbacks *uri_cb, std::string *out_uri, void *);
#endif
///
@@ -1388,6 +1426,11 @@ class TinyGLTF {
///
void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
+ ///
+ /// Set callbacks to use for URI encoding and decoding and their user data
+ ///
+ void SetURICallbacks(URICallbacks callbacks);
+
///
/// Set callbacks to use for filesystem (fs) access and their user data
///
@@ -1470,6 +1513,15 @@ class TinyGLTF {
#endif
};
+ URICallbacks uri_cb = {
+ // Use paths as-is by default. This will use JSON string escaping.
+ nullptr,
+ // Decode all URIs before using them as paths as the application may have
+ // percent encoded them.
+ &tinygltf::URIDecode,
+ // URI callback user data
+ nullptr};
+
LoadImageDataFunction LoadImageData =
#ifndef TINYGLTF_NO_STB_IMAGE
&tinygltf::LoadImageData;
@@ -2291,6 +2343,13 @@ static const std::string urldecode(const std::string &str) {
} // namespace dlib
// --- dlib end --------------------------------------------------------------
+bool URIDecode(const std::string &in_uri, std::string *out_uri,
+ void *user_data) {
+ (void)user_data;
+ *out_uri = dlib::urldecode(in_uri);
+ return true;
+}
+
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
std::string *warn, const std::string &filename,
const std::string &basedir, bool required,
@@ -2501,7 +2560,8 @@ static void WriteToMemory_stbi(void *context, void *data, int size) {
}
bool WriteImageData(const std::string *basepath, const std::string *filename,
- const Image *image, bool embedImages, std::string *out_uri,
+ const Image *image, bool embedImages,
+ const URICallbacks *uri_cb, std::string *out_uri,
void *fsPtr) {
const std::string ext = GetFilePathExtension(*filename);
@@ -2563,13 +2623,26 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
} else {
// Throw error?
}
- *out_uri = *filename;
+ if (uri_cb->encode) {
+ if (!uri_cb->encode(*filename, "image", out_uri, uri_cb->user_data)) {
+ return false;
+ }
+ } else {
+ *out_uri = *filename;
+ }
}
return true;
}
#endif
+void TinyGLTF::SetURICallbacks(URICallbacks callbacks) {
+ assert(callbacks.decode);
+ if (callbacks.decode) {
+ uri_cb = callbacks;
+ }
+}
+
void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
#ifdef _WIN32
@@ -2834,15 +2907,21 @@ static std::string MimeToExt(const std::string &mimeType) {
return "";
}
-static void UpdateImageObject(const Image &image, std::string &baseDir,
+static bool UpdateImageObject(const Image &image, std::string &baseDir,
int index, bool embedImages,
+ const URICallbacks *uri_cb,
WriteImageDataFunction *WriteImageData,
- std::string *out_uri, void *user_data) {
+ void *user_data, std::string *out_uri) {
std::string filename;
std::string ext;
// If image has uri, use it as a filename
if (image.uri.size()) {
- filename = GetBaseFilename(image.uri);
+ std::string decoded_uri;
+ if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) {
+ // A decode failure results in a failure to write the gltf.
+ return false;
+ }
+ filename = GetBaseFilename(decoded_uri);
ext = GetFilePathExtension(filename);
} else if (image.bufferView != -1) {
// If there's no URI and the data exists in a buffer,
@@ -2857,17 +2936,24 @@ static void UpdateImageObject(const Image &image, std::string &baseDir,
filename = std::to_string(index) + "." + ext;
}
- // If callback is set, modify image data object
+ // If callback is set and image data exists, modify image data object. If
+ // image data does not exist, this is not considered a failure and the
+ // original uri should be maintained.
bool imageWritten = false;
- if (*WriteImageData != nullptr && !filename.empty()) {
+ if (*WriteImageData != nullptr && !filename.empty() && !image.image.empty()) {
imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages,
- out_uri, user_data);
+ uri_cb, out_uri, user_data);
+ if (!imageWritten) {
+ return false;
+ }
}
// Use the original uri if the image was not written.
if (!imageWritten) {
*out_uri = image.uri;
}
+
+ return true;
}
bool IsDataURI(const std::string &in) {
@@ -3786,6 +3872,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
std::string *warn, const json &o,
bool store_original_json_for_extras_and_extensions,
const std::string &basedir, FsCallbacks *fs,
+ const URICallbacks *uri_cb,
LoadImageDataFunction *LoadImageData = nullptr,
void *load_image_user_data = nullptr) {
// A glTF image must either reference a bufferView or an image uri
@@ -3896,7 +3983,18 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
return true;
#else
- std::string decoded_uri = dlib::urldecode(uri);
+ std::string decoded_uri;
+ if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) {
+ if (warn) {
+ (*warn) += "Failed to decode 'uri' for image[" +
+ std::to_string(image_idx) + "] name = [" + image->name +
+ "]\n";
+ }
+
+ // Image loading failure is not critical to overall gltf loading.
+ return true;
+ }
+
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
/* required */ false, /* required bytes */ 0,
/* checksize */ false, fs)) {
@@ -4075,8 +4173,8 @@ static bool ParseOcclusionTextureInfo(
static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
bool store_original_json_for_extras_and_extensions,
- FsCallbacks *fs, const std::string &basedir,
- bool is_binary = false,
+ FsCallbacks *fs, const URICallbacks *uri_cb,
+ const std::string &basedir, bool is_binary = false,
const unsigned char *bin_data = nullptr,
size_t bin_size = 0) {
size_t byteLength;
@@ -4122,7 +4220,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
}
} else {
// External .bin file.
- std::string decoded_uri = dlib::urldecode(buffer->uri);
+ std::string decoded_uri;
+ if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
+ return false;
+ }
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
decoded_uri, basedir, /* required */ true,
byteLength, /* checkSize */ true, fs)) {
@@ -4167,7 +4268,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
}
} else {
// Assume external .bin file.
- std::string decoded_uri = dlib::urldecode(buffer->uri);
+ std::string decoded_uri;
+ if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
+ return false;
+ }
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri,
basedir, /* required */ true, byteLength,
/* checkSize */ true, fs)) {
@@ -5000,12 +5104,7 @@ static bool ParseAnimationChannel(
if (FindMember(o, "target", targetIt) && IsObject(GetValue(targetIt))) {
const json &target_object = GetValue(targetIt);
- if (!ParseIntegerProperty(&targetIndex, err, target_object, "node", true)) {
- if (err) {
- (*err) += "`node` field is missing in animation.channels.target\n";
- }
- return false;
- }
+ ParseIntegerProperty(&targetIndex, err, target_object, "node", false);
if (!ParseStringProperty(&channel->target_path, err, target_object, "path",
true)) {
@@ -5710,7 +5809,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
Buffer buffer;
if (!ParseBuffer(&buffer, err, o,
store_original_json_for_extras_and_extensions_, &fs,
- base_dir, is_binary_, bin_data_, bin_size_)) {
+ &uri_cb, base_dir, is_binary_, bin_data_, bin_size_)) {
return false;
}
@@ -5981,7 +6080,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
Image image;
if (!ParseImage(&image, idx, err, warn, o,
store_original_json_for_extras_and_extensions_, base_dir,
- &fs, &this->LoadImageData, load_image_user_data)) {
+ &fs, &uri_cb, &this->LoadImageData,
+ load_image_user_data)) {
return false;
}
@@ -6864,7 +6964,11 @@ static void SerializeGltfAnimationChannel(const AnimationChannel &channel,
SerializeNumberProperty("sampler", channel.sampler, o);
{
json target;
- SerializeNumberProperty("node", channel.target_node, target);
+
+ if (channel.target_node > 0) {
+ SerializeNumberProperty("node", channel.target_node, target);
+ }
+
SerializeStringProperty("path", channel.target_path, target);
SerializeExtensionMap(channel.target_extensions, target);
@@ -6977,10 +7081,10 @@ static void SerializeGltfBuffer(const Buffer &buffer, json &o) {
static bool SerializeGltfBuffer(const Buffer &buffer, json &o,
const std::string &binFilename,
- const std::string &binBaseFilename) {
+ const std::string &binUri) {
if (!SerializeGltfBufferData(buffer.data, binFilename)) return false;
SerializeNumberProperty("byteLength", buffer.data.size(), o);
- SerializeStringProperty("uri", binBaseFilename, o);
+ SerializeStringProperty("uri", binUri, o);
if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o);
@@ -7016,7 +7120,7 @@ static void SerializeGltfBufferView(const BufferView &bufferView, json &o) {
}
}
-static void SerializeGltfImage(const Image &image, const std::string uri,
+static void SerializeGltfImage(const Image &image, const std::string &uri,
json &o) {
// From 2.7.0, we look for `uri` parameter, not `Image.uri`
// if uri is empty, the mimeType and bufferview should be set
@@ -7024,7 +7128,6 @@ static void SerializeGltfImage(const Image &image, const std::string uri,
SerializeStringProperty("mimeType", image.mimeType, o);
SerializeNumberProperty<int>("bufferView", image.bufferView, o);
} else {
- // TODO(syoyo): dlib::urilencode?
SerializeStringProperty("uri", uri, o);
}
@@ -7338,6 +7441,9 @@ static void SerializeGltfNode(const Node &node, json &o) {
}
static void SerializeGltfSampler(const Sampler &sampler, json &o) {
+ if (!sampler.name.empty()) {
+ SerializeStringProperty("name", sampler.name, o);
+ }
if (sampler.magFilter != -1) {
SerializeNumberProperty("magFilter", sampler.magFilter, o);
}
@@ -7817,9 +7923,11 @@ bool TinyGLTF::WriteGltfSceneToStream(const Model *model, std::ostream &stream,
// enabled, since we won't write separate images when writing to a stream
// we
std::string uri;
- UpdateImageObject(model->images[i], dummystring, int(i), true,
- &this->WriteImageData, &uri,
- this->write_image_user_data_);
+ if (!UpdateImageObject(model->images[i], dummystring, int(i), true,
+ &uri_cb, &this->WriteImageData,
+ this->write_image_user_data_, &uri)) {
+ return false;
+ }
SerializeGltfImage(model->images[i], uri, image);
JsonPushBack(images, std::move(image));
}
@@ -7856,7 +7964,7 @@ bool TinyGLTF::WriteGltfSceneToFile(const Model *model,
SerializeGltfModel(model, output);
// BUFFERS
- std::vector<std::string> usedUris;
+ std::vector<std::string> usedFilenames;
std::vector<unsigned char> binBuffer;
if (model->buffers.size()) {
json buffers;
@@ -7869,27 +7977,40 @@ bool TinyGLTF::WriteGltfSceneToFile(const Model *model,
SerializeGltfBuffer(model->buffers[i], buffer);
} else {
std::string binSavePath;
+ std::string binFilename;
std::string binUri;
if (!model->buffers[i].uri.empty() &&
!IsDataURI(model->buffers[i].uri)) {
binUri = model->buffers[i].uri;
+ if (!uri_cb.decode(binUri, &binFilename, uri_cb.user_data)) {
+ return false;
+ }
} else {
- binUri = defaultBinFilename + defaultBinFileExt;
+ binFilename = defaultBinFilename + defaultBinFileExt;
bool inUse = true;
int numUsed = 0;
while (inUse) {
inUse = false;
- for (const std::string &usedName : usedUris) {
- if (binUri.compare(usedName) != 0) continue;
+ for (const std::string &usedName : usedFilenames) {
+ if (binFilename.compare(usedName) != 0) continue;
inUse = true;
- binUri = defaultBinFilename + std::to_string(numUsed++) +
- defaultBinFileExt;
+ binFilename = defaultBinFilename + std::to_string(numUsed++) +
+ defaultBinFileExt;
break;
}
}
+
+ if (uri_cb.encode) {
+ if (!uri_cb.encode(binFilename, "buffer", &binUri,
+ uri_cb.user_data)) {
+ return false;
+ }
+ } else {
+ binUri = binFilename;
+ }
}
- usedUris.push_back(binUri);
- binSavePath = JoinPath(baseDir, binUri);
+ usedFilenames.push_back(binFilename);
+ binSavePath = JoinPath(baseDir, binFilename);
if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
binUri)) {
return false;
@@ -7908,9 +8029,11 @@ bool TinyGLTF::WriteGltfSceneToFile(const Model *model,
json image;
std::string uri;
- UpdateImageObject(model->images[i], baseDir, int(i), embedImages,
- &this->WriteImageData, &uri,
- this->write_image_user_data_);
+ if (!UpdateImageObject(model->images[i], baseDir, int(i), embedImages,
+ &uri_cb, &this->WriteImageData,
+ this->write_image_user_data_, &uri)) {
+ return false;
+ }
SerializeGltfImage(model->images[i], uri, image);
JsonPushBack(images, std::move(image));
}