Compare commits

..

42 Commits

Author SHA1 Message Date
Syoyo Fujita
584f1dfbe4 Merge branch 'release' of github.com:syoyo/tinygltf into release 2022-12-29 21:13:48 +09:00
Syoyo Fujita
a40ca4c5ab Merge pull request #393 from pknowlesnv/serialize_const
allow serializing a const Model
2022-12-29 21:00:24 +09:00
Pyarelal Knowles
de75d87cfd allow serializing a const Model
Adds 'const' to all Serialize*() methods.

Updates WriteImageData callback to take a URI out pointer that was
previously being written to the Image::uri, which is now const.

This breaks the WriteImageData API and as a side effect, Image::uri will
no longer contain the written image URI after saving.

Adds test serialize-const-image, which verifies the model's image is not
changed (because it's const), but the uri written to the gltf json is
still correct.

Adds test serialize-image-callback that defines a WriteImageDataFunction
and also verifies the uri can be overwritten.
2022-12-28 17:20:09 -08:00
Syoyo Fujita
cf11842e64 Merge pull request #395 from ethanpepro/cmake-export
Add CMake export configuration
2022-12-28 18:33:36 +09:00
James Luke
38003032e3 Add CMake export configuration 2022-12-27 21:12:54 -05:00
Syoyo Fujita
186016bf11 Merge branch 'release' of github.com:syoyo/tinygltf into release 2022-12-03 19:42:27 +09:00
Syoyo Fujita
5ee08f9274 Remove Python 2 description. 2022-12-03 19:40:50 +09:00
Syoyo Fujita
aa613a1f57 Update README.md
Remove Python 2.x description
2022-12-03 19:40:45 +09:00
Syoyo Fujita
222454cc6d Create FUNDING.yml 2022-12-03 18:33:05 +09:00
Syoyo Fujita
16c2d3a8bf Merge pull request #390 from eduardodoria/patch-1
Added Supernova Engine to Projects using TinyGLTF
2022-11-07 21:18:50 +09:00
Eduardo Doria
186093657a Added Supernova Engine to Projects using TinyGLTF 2022-11-07 08:53:47 -03:00
Syoyo Fujita
9bdd256625 Merge pull request #388 from stromaster/patch-1
Avoid multiple asset_manager definitions on Android
2022-10-31 17:40:40 +09:00
Serdar Kocdemir
264ae4c131 Avoid multiple asset_manager definition on Android
Using TINYGLTF_IMPLEMENTATION to make the actual definition of the 'asset_manager' global variable.
2022-10-30 22:32:59 +00:00
Syoyo Fujita
091a1fcc1a Merge pull request #386 from geometrian/master
Fix Clang Compile Warnings/Errors (and Typos)
2022-10-08 19:08:22 +09:00
imallett
3a295887d6 Patch to fix previous commit for MinGW. 2022-10-07 11:20:39 -07:00
imallett
d9ce9eb9d2 Fix a gazillion typos. 2022-10-07 10:37:09 -07:00
imallett
56e1098993 Fix various type mismatches and header include case (fixes compile warnings on Clang). 2022-10-07 10:35:16 -07:00
Syoyo Fujita
9bb5806df4 Merge pull request #385 from operatios/master
Fix UTF-8 filepath on LLVM MinGW
2022-09-25 05:35:36 +09:00
operatios
1668d1ecc5 Fix UTF-8 filepath on LLVM MinGW 2022-09-24 22:37:14 +03:00
Syoyo Fujita
6e8a858c45 Add WASI build procedure. 2022-09-22 04:36:58 +09:00
Syoyo Fujita
e0b625561c v2.6.3 2022-09-19 03:36:58 +09:00
Syoyo Fujita
18450eafe7 Merge pull request #382 from syoyo/glb-zero-chunk
Fix parsing GLB file with empty Chunk1(BIN data).
2022-09-19 03:34:09 +09:00
Syoyo Fujita
e9fbc03e2d Clear error/warn message. 2022-09-19 03:29:57 +09:00
Syoyo Fujita
612e57816f Fix handling <4 byte BIN data.
Fix handling GLB file with empty CHUNK1(BIN).
2022-09-18 21:01:39 +09:00
Kh4n
a778c089d1 readd toplevel makefile 2022-09-17 15:39:28 -05:00
Kh4n
387fd61b83 update test to match gltf-validator 2022-09-17 13:02:39 -05:00
Kh4n
6514490090 update gitignore to remove test file
readd accidental removals in gitignore

undo autoformat

more undo autoformatting
2022-09-17 12:52:59 -05:00
Kh4n
6b7ec9f494 added tests to cover empty, empty buffer, and single byte buffer cases 2022-09-17 12:28:39 -05:00
Syoyo Fujita
c670f08a3b Fix parsing GLB file with empty Chunk1(BIN data). 2022-09-17 19:52:25 +09:00
Syoyo Fujita
eec4c98862 Add note on v2.6.2(Fix out-of-bounds access of accessors. PR#379) 2022-09-16 17:27:20 +09:00
Syoyo Fujita
c7e911cf11 Merge pull request #380 from AlvaroBarua/master
Fixes compiler warning on VS (Unreachable code detected)
2022-09-11 17:56:55 +09:00
AlvaroBarua
43172238f7 Fixes compiler warning on VS (Unreachable code detected) 2022-09-11 00:41:43 +01:00
Syoyo Fujita
0cc23356dc Merge pull request #379 from nirmal/patch-1
Fix possible out of bounds index in LoadFromString
2022-09-07 01:52:55 +09:00
Nirmal Patel
e413216722 Fix possible out of bounds index in LoadFromString 2022-09-06 09:16:31 -07:00
Syoyo Fujita
4581d37bec v2.6.1 2022-09-06 22:02:31 +09:00
Syoyo Fujita
966a9d0df7 Merge pull request #374 from syoyo/glb_chunk_check
Better GLB data size check when reading.
2022-09-06 21:35:47 +09:00
Syoyo Fujita
64452bb5fa Merge pull request #377 from zbendefy/master
Auto detect C++14 standard version
2022-09-06 14:01:26 +09:00
zbendefy
69eeea145b Auto detect C++14 standard version 2022-09-05 23:54:57 +02:00
Syoyo Fujita
24e539621d Merge pull request #376 from kacprzak/master
Read from moved object
2022-09-03 01:16:41 +09:00
Marcin Kacprzak
f4f5c3cf3a Fix read from moved object. 2022-09-02 16:15:54 +02:00
Marcin Kacprzak
b12a54ed15 Silence MS code analysis tool. 2022-09-02 16:13:11 +02:00
Syoyo Fujita
240d993f94 Create codeql-analysis.yml 2022-09-02 05:09:09 +09:00
12 changed files with 488 additions and 177 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: syoyo
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

72
.github/workflows/codeql-analysis.yml vendored Normal file
View 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
View File

@@ -68,4 +68,11 @@ loader_example
tests/tester
tests/tester_noexcept
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

View File

@@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.6)
PROJECT (tinygltf)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
SET(CMAKE_CXX_STANDARD 11)
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
@@ -54,7 +57,10 @@ else (TINYGLTF_HEADER_ONLY)
endif (TINYGLTF_HEADER_ONLY)
if (TINYGLTF_INSTALL)
install(TARGETS tinygltf EXPORT tinygltfTargets)
install(EXPORT tinygltfTargets NAMESPACE tinygltf:: FILE TinyGLTFTargets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/TinyGLTFConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TinyGLTFConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
# Do not install .lib even if !TINYGLTF_HEADER_ONLY
INSTALL ( FILES
@@ -67,10 +73,4 @@ if (TINYGLTF_INSTALL)
include
)
INSTALL ( FILES
cmake/TinyGLTFConfig.cmake
DESTINATION
cmake
)
endif(TINYGLTF_INSTALL)

View File

@@ -86,6 +86,12 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [basic](examples/basic) : Basic glTF viewer with texturing support.
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
### WASI/WASM build
Users who want to run TinyGLTF securely and safely(e.g. need to handle malcious glTF file to serve online glTF conver),
I recommend to build TinyGLTF for WASM target.
WASI build example is located in [wasm](wasm) .
## Projects using TinyGLTF
* px_render Single header C++ Libraries for Thread Scheduling, Rendering, and so on... https://github.com/pplux/px
@@ -100,6 +106,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [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
* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing
* [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design.
* Your projects here! (Please send PR)
## TODOs
@@ -222,7 +229,7 @@ add_subdirectory(/path/to/tinygltf)
#### Setup
Python 2.6 or 2.7 required.
Python required.
Git clone https://github.com/KhronosGroup/glTF-Sample-Models to your local dir.
#### Run parsing test

View File

@@ -1,15 +0,0 @@
# -*- cmake -*-
# - Find TinyGLTF
# TinyGLTF_INCLUDE_DIR TinyGLTF's include directory
FIND_PACKAGE ( PackageHandleStandardArgs )
SET ( TinyGLTF_INCLUDE_DIR "${TinyGLTF_DIR}/../include" CACHE STRING "TinyGLTF include directory")
FIND_FILE ( TinyGLTF_HEADER tiny_gltf.h PATHS ${TinyGLTF_INCLUDE_DIR} )
IF (NOT TinyGLTF_HEADER)
MESSAGE ( FATAL_ERROR "Unable to find tiny_gltf.h, TinyGLTF_INCLUDE_DIR = ${TinyGLTF_INCLUDE_DIR}")
ENDIF ()

View File

@@ -0,0 +1,3 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/TinyGLTFTargets.cmake)

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env python
# Assume python 2.6 or 2.7
import glob
import os
import subprocess

View File

@@ -482,3 +482,124 @@ TEST_CASE("expandpath-utf-8", "[pr-226]") {
}
#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);
}
TEST_CASE("serialize-const-image", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
i.width = 1;
i.height = 1;
i.component = 4;
i.bits = 8;
i.pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
i.image = {255, 255, 255, 255};
i.uri = "image.png";
m.images.push_back(i);
std::stringstream os;
tinygltf::TinyGLTF ctx;
ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
REQUIRE(m.images[0].uri == i.uri);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() != i.uri);
REQUIRE(j["images"][0]["uri"].get<std::string>().rfind("data:", 0) == 0);
}
TEST_CASE("serialize-image-callback", "[issue-394]") {
tinygltf::Model m;
tinygltf::Image i;
i.width = 1;
i.height = 1;
i.bits = 32;
i.image = {255, 255, 255, 255};
i.uri = "foo";
m.images.push_back(i);
std::stringstream os;
auto writer = [](const std::string *basepath, const std::string *filename,
const tinygltf::Image *image, bool embedImages,
std::string *out_uri, void *user_pointer) -> bool {
REQUIRE(*filename == "foo");
REQUIRE(embedImages == true);
REQUIRE(user_pointer == (void *)0xba5e1e55);
*out_uri = "bar";
return true;
};
tinygltf::TinyGLTF ctx;
ctx.SetImageWriter(writer, (void *)0xba5e1e55);
ctx.WriteGltfSceneToStream(const_cast<const tinygltf::Model *>(&m), os, false,
false);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(1 == j["images"].size());
REQUIRE(j["images"][0].is_object());
REQUIRE(j["images"][0]["uri"].get<std::string>() == "bar");
}

View File

@@ -26,10 +26,14 @@
// THE SOFTWARE.
// Version:
// - 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.
// - 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.4.3 Fix null object output when when material has all default
// - v2.4.3 Fix null object output when material has all default
// parameters.
// - v2.4.2 Decode percent-encoded URI.
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or
@@ -43,7 +47,7 @@
// - v2.2.0 Add loading 16bit PNG support. Add Sparse accessor support(Thanks
// to @Ybalrid)
// - v2.1.0 Add draco compression.
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
// - v2.0.1 Add comparison feature(Thanks to @Selmar).
// - v2.0.0 glTF 2.0!.
//
// Tiny glTF loader is using following third party libraries:
@@ -66,6 +70,11 @@
#include <string>
#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
#include <functional>
#endif
@@ -192,7 +201,11 @@ namespace tinygltf {
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
#ifdef TINYGLTF_IMPLEMENTATION
AAssetManager *asset_manager = nullptr;
#else
extern AAssetManager *asset_manager;
#endif
#endif
#endif
@@ -225,7 +238,7 @@ static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
} else if (componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
return 8;
} else {
// Unknown componenty type
// Unknown component type
return -1;
}
}
@@ -246,7 +259,7 @@ static inline int32_t GetNumComponentsInType(uint32_t ty) {
} else if (ty == TINYGLTF_TYPE_MAT4) {
return 16;
} else {
// Unknown componenty type
// Unknown component type
return -1;
}
}
@@ -433,7 +446,7 @@ TINYGLTF_VALUE_GET(Value::Object, object_value_)
#pragma clang diagnostic ignored "-Wpadded"
#endif
/// Agregate object for representing a color
/// Aggregate object for representing a color
using ColorValue = std::array<double, 4>;
// === legacy interface ====
@@ -470,7 +483,7 @@ struct Parameter {
if (it != std::end(json_double_value)) {
return int(it->second);
}
// As per the spec, if texCoord is ommited, this parameter is 0
// As per the spec, if texCoord is omitted, this parameter is 0
return 0;
}
@@ -482,7 +495,7 @@ struct Parameter {
if (it != std::end(json_double_value)) {
return it->second;
}
// As per the spec, if scale is ommited, this paramter is 1
// As per the spec, if scale is omitted, this parameter is 1
return 1;
}
@@ -494,7 +507,7 @@ struct Parameter {
if (it != std::end(json_double_value)) {
return it->second;
}
// As per the spec, if strenghth is ommited, this parameter is 1
// As per the spec, if strength is omitted, this parameter is 1
return 1;
}
@@ -508,7 +521,7 @@ struct Parameter {
/// material
ColorValue ColorFactor() const {
return {
{// this agregate intialize the std::array object, and uses C++11 RVO.
{// this aggregate initialize the std::array object, and uses C++11 RVO.
number_array[0], number_array[1], number_array[2],
(number_array.size() > 3 ? number_array[3] : 1.0)}};
}
@@ -819,7 +832,7 @@ struct BufferView {
size_t byteStride{0}; // minimum 4, maximum 252 (multiple of 4), default 0 =
// understood to be tightly packed
int target{0}; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices
// or atttribs. Could be 0 for other data
// or attribs. Could be 0 for other data
Value extras;
ExtensionMap extensions;
@@ -895,7 +908,7 @@ struct Accessor {
return componentSizeInBytes * numComponents;
} else {
// Check if byteStride is a mulple of the size of the accessor's component
// Check if byteStride is a multiple of the size of the accessor's component
// type.
int componentSizeInBytes =
GetComponentSizeInBytes(static_cast<uint32_t>(componentType));
@@ -934,7 +947,7 @@ struct PerspectiveCamera {
PerspectiveCamera()
: aspectRatio(0.0),
yfov(0.0),
zfar(0.0) // 0 = use infinite projecton matrix
zfar(0.0) // 0 = use infinite projection matrix
,
znear(0.0) {}
DEFAULT_METHODS(PerspectiveCamera)
@@ -995,7 +1008,7 @@ struct Primitive {
int indices; // The index of the accessor that contains the indices.
int mode; // one of TINYGLTF_MODE_***
std::vector<std::map<std::string, int> > targets; // array of morph targets,
// where each target is a dict with attribues in ["POSITION, "NORMAL",
// where each target is a dict with attributes in ["POSITION, "NORMAL",
// "TANGENT"] pointing
// to their corresponding accessors
ExtensionMap extensions;
@@ -1130,7 +1143,7 @@ struct Light {
std::vector<double> color;
double intensity{1.0};
std::string type;
double range{0.0}; // 0.0 = inifinite
double range{0.0}; // 0.0 = infinite
SpotLight spot;
Light() : intensity(1.0), range(0.0) {}
@@ -1204,9 +1217,13 @@ typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
///
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
/// The out_uri parameter becomes the URI written to the gltf and may reference
/// a file or contain a data URI.
///
typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *,
Image *, bool, void *);
typedef bool (*WriteImageDataFunction)(const std::string *basepath,
const std::string *filename,
const Image *image, bool embedImages,
std::string *out_uri, void *user_pointer);
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
@@ -1218,7 +1235,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,
Image *image, bool embedImages, void *);
const Image *image, bool embedImages, std::string *out_uri,
void *);
#endif
///
@@ -1280,7 +1298,7 @@ bool WriteWholeFile(std::string *err, const std::string &filepath,
#endif
///
/// glTF Parser/Serialier context.
/// glTF Parser/Serializer context.
///
class TinyGLTF {
public:
@@ -1343,15 +1361,15 @@ class TinyGLTF {
unsigned int check_sections = REQUIRE_VERSION);
///
/// Write glTF to stream, buffers and images will be embeded
/// Write glTF to stream, buffers and images will be embedded
///
bool WriteGltfSceneToStream(Model *model, std::ostream &stream,
bool WriteGltfSceneToStream(const Model *model, std::ostream &stream,
bool prettyPrint, bool writeBinary);
///
/// Write glTF to file.
///
bool WriteGltfSceneToFile(Model *model, const std::string &filename,
bool WriteGltfSceneToFile(const Model *model, const std::string &filename,
bool embedImages, bool embedBuffers,
bool prettyPrint, bool writeBinary);
@@ -1378,7 +1396,7 @@ class TinyGLTF {
///
/// Set serializing default values(default = false).
/// When true, default values are force serialized to .glTF.
/// This may be helpfull if you want to serialize a full description of glTF
/// This may be helpful if you want to serialize a full description of glTF
/// data.
///
/// TODO(LTE): Supply parsing option as function arguments to
@@ -1404,8 +1422,8 @@ class TinyGLTF {
}
///
/// Specify whether preserve image channales when loading images or not.
/// (Not effective when the user suppy their own LoadImageData callbacks)
/// Specify whether preserve image channels when loading images or not.
/// (Not effective when the user supplies their own LoadImageData callbacks)
///
void SetPreserveImageChannels(bool onoff) {
preserve_image_channels_ = onoff;
@@ -1542,7 +1560,7 @@ class TinyGLTF {
#endif
#endif
// Disable GCC warnigs
// Disable GCC warnings
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
@@ -1591,7 +1609,7 @@ class TinyGLTF {
// issue 143.
// Define NOMINMAX to avoid min/max defines,
// but undef it after included windows.h
// but undef it after included Windows.h
#ifndef NOMINMAX
#define TINYGLTF_INTERNAL_NOMINMAX
#define NOMINMAX
@@ -1601,7 +1619,11 @@ class TinyGLTF {
#define WIN32_LEAN_AND_MEAN
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> // include API for expanding a file path
#ifndef __MINGW32__
#include <Windows.h> // include API for expanding a file path
#else
#include <windows.h>
#endif
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
@@ -1732,7 +1754,7 @@ namespace tinygltf {
struct LoadImageDataOption {
// true: preserve image channels(e.g. load as RGB image if the image has RGB
// channels) default `false`(channels are expanded to RGBA for backward
// compatiblity).
// compatibility).
bool preserve_channels{false};
};
@@ -2379,7 +2401,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
// It is possible that the image we want to load is a 16bit per channel image
// We are going to attempt to load it as 16bit per channel, and if it worked,
// set the image data accodingly. We are casting the returned pointer into
// set the image data accordingly. We are casting the returned pointer into
// unsigned char, because we are representing "bytes". But we are updating
// the Image metadata to signal that this image uses 2 bytes (16bits) per
// channel:
@@ -2394,7 +2416,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
// at this point, if data is still NULL, it means that the image wasn't
// 16bit per channel, we are going to load it as a normal 8bit per channel
// mage as we used to do:
// image as we used to do:
// if image cannot be decoded, ignore parsing and keep it by its path
// don't break in this case
// FIXME we should only enter this function if the image is embedded. If
@@ -2479,7 +2501,8 @@ static void WriteToMemory_stbi(void *context, void *data, int size) {
}
bool WriteImageData(const std::string *basepath, const std::string *filename,
Image *image, bool embedImages, void *fsPtr) {
const Image *image, bool embedImages, std::string *out_uri,
void *fsPtr) {
const std::string ext = GetFilePathExtension(*filename);
// Write image to temporary buffer
@@ -2521,9 +2544,8 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
if (embedImages) {
// Embed base64-encoded image into URI
if (data.size()) {
image->uri =
header +
base64_encode(&data[0], static_cast<unsigned int>(data.size()));
*out_uri = header +
base64_encode(&data[0], static_cast<unsigned int>(data.size()));
} else {
// Throw error?
}
@@ -2541,7 +2563,7 @@ bool WriteImageData(const std::string *basepath, const std::string *filename,
} else {
// Throw error?
}
image->uri = *filename;
*out_uri = *filename;
}
return true;
@@ -2554,7 +2576,7 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
static inline std::wstring UTF8ToWchar(const std::string &str) {
int wstr_size =
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
std::wstring wstr(wstr_size, 0);
std::wstring wstr((size_t)wstr_size, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0],
(int)wstr.size());
return wstr;
@@ -2562,10 +2584,10 @@ static inline std::wstring UTF8ToWchar(const std::string &str) {
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);
nullptr, 0, nullptr, nullptr);
std::string str((size_t)str_size, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
(int)str.size(), NULL, NULL);
(int)str.size(), nullptr, nullptr);
return str;
}
#endif
@@ -2589,7 +2611,7 @@ bool FileExists(const std::string &abs_filename, void *) {
}
#else
#ifdef _WIN32
#if defined(_MSC_VER) || defined(__GLIBCXX__)
#if defined(_MSC_VER) || defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
FILE *fp = nullptr;
errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb");
if (err != 0) {
@@ -2812,13 +2834,13 @@ static std::string MimeToExt(const std::string &mimeType) {
return "";
}
static void UpdateImageObject(Image &image, std::string &baseDir, int index,
bool embedImages,
WriteImageDataFunction *WriteImageData = nullptr,
void *user_data = nullptr) {
static void UpdateImageObject(const Image &image, std::string &baseDir,
int index, bool embedImages,
WriteImageDataFunction *WriteImageData,
std::string *out_uri, void *user_data) {
std::string filename;
std::string ext;
// If image has uri, use it it as a filename
// If image has uri, use it as a filename
if (image.uri.size()) {
filename = GetBaseFilename(image.uri);
ext = GetFilePathExtension(filename);
@@ -2836,9 +2858,15 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index,
}
// If callback is set, modify image data object
bool imageWritten = false;
if (*WriteImageData != nullptr && !filename.empty()) {
std::string uri;
(*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data);
imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages,
out_uri, user_data);
}
// Use the original uri if the image was not written.
if (!imageWritten) {
*out_uri = image.uri;
}
}
@@ -3229,9 +3257,11 @@ static bool ParseJsonAsValue(Value *ret, const json &o) {
break;
}
#endif
const bool isNotNull = val.Type() != NULL_TYPE;
if (ret) *ret = std::move(val);
return val.Type() != NULL_TYPE;
return isNotNull;
}
static bool ParseExtrasProperty(Value *ret, const json &o) {
@@ -3671,7 +3701,8 @@ static bool ParseParameterProperty(Parameter *param, std::string *err,
// Found a number array.
return true;
} else if (ParseNumberProperty(&param->number_value, err, o, prop, false)) {
return param->has_number_value = true;
param->has_number_value = true;
return true;
} else if (ParseJSONProperty(&param->json_double_value, err, o, prop,
false)) {
return true;
@@ -3864,7 +3895,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
image->uri = uri;
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
return true;
#endif
#else
std::string decoded_uri = dlib::urldecode(uri);
if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
/* required */ false, /* required bytes */ 0,
@@ -3886,6 +3917,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
}
return false;
}
#endif
}
if (*LoadImageData == nullptr) {
@@ -4102,7 +4134,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
if ((bin_size == 0) || (bin_data == nullptr)) {
if (err) {
(*err) += "Invalid binary data in `Buffer'.\n";
(*err) += "Invalid binary data in `Buffer', or GLB with empty BIN chunk.\n";
}
return false;
}
@@ -4260,7 +4292,7 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
}
if (!FindMember(o, "values", values_iterator)) {
(*err) = "the sparse object ob ths accessor doesn't have values";
(*err) = "the sparse object of this accessor doesn't have values";
return false;
}
@@ -4606,7 +4638,7 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
int mode = TINYGLTF_MODE_TRIANGLES;
ParseIntegerProperty(&mode, err, o, "mode", false);
primitive->mode = mode; // Why only triangled were supported ?
primitive->mode = mode; // Why only triangles were supported ?
int indices = -1;
ParseIntegerProperty(&indices, err, o, "indices", false);
@@ -4889,7 +4921,7 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o,
// Old code path. For backward compatibility, we still store material values
// as Parameter. This will create duplicated information for
// example(pbrMetallicRoughness), but should be neglible in terms of memory
// example(pbrMetallicRoughness), but should be negligible in terms of memory
// consumption.
// TODO(syoyo): Remove in the next major release.
material->values.clear();
@@ -4922,7 +4954,7 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o,
Parameter param;
if (ParseParameterProperty(&param, err, o, key, false)) {
// names of materials have already been parsed. Putting it in this map
// doesn't correctly reflext the glTF specification
// doesn't correctly reflect the glTF specification
if (key != "name")
material->additionalValues.emplace(std::move(key), std::move(param));
}
@@ -5128,7 +5160,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o,
// ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf
// extension
// TODO(syoyo): Check the value is alloed one.
// TODO(syoyo): Check the value is allowed one.
// (e.g. we allow 9728(NEAREST), but don't allow 9727)
sampler->minFilter = minFilter;
@@ -5337,7 +5369,7 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o,
if (!FindMember(o, "orthographic", orthoIt)) {
if (err) {
std::stringstream ss;
ss << "Orhographic camera description not found." << std::endl;
ss << "Orthographic camera description not found." << std::endl;
(*err) += ss.str();
}
return false;
@@ -5789,25 +5821,32 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// we could optionally check if acessors' bufferView type is Scalar, as
// we could optionally check if accessors' bufferView type is Scalar, as
// it should be
}
for (auto &attribute : primitive.attributes) {
model
->bufferViews[size_t(
model->accessors[size_t(attribute.second)].bufferView)]
.target = TINYGLTF_TARGET_ARRAY_BUFFER;
const auto accessorsIndex = size_t(attribute.second);
if (accessorsIndex < model->accessors.size()) {
const auto bufferView = model->accessors[accessorsIndex].bufferView;
// bufferView could be null(-1) for sparse morph target
if (bufferView >= 0 && bufferView < (int)model->bufferViews.size()) {
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ARRAY_BUFFER;
}
}
}
for (auto &target : primitive.targets) {
for (auto &attribute : target) {
auto bufferView =
model->accessors[size_t(attribute.second)].bufferView;
// bufferView could be null(-1) for sparse morph target
if (bufferView >= 0) {
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ARRAY_BUFFER;
const auto accessorsIndex = size_t(attribute.second);
if (accessorsIndex < model->accessors.size()) {
const auto bufferView = model->accessors[accessorsIndex].bufferView;
// bufferView could be null(-1) for sparse morph target
if (bufferView >= 0 && bufferView < (int)model->bufferViews.size()) {
model->bufferViews[size_t(bufferView)].target =
TINYGLTF_TARGET_ARRAY_BUFFER;
}
}
}
}
@@ -6268,15 +6307,15 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
//
// https://github.com/syoyo/tinygltf/issues/372
// Use 64bit uint to avoid integer overflow.
uint64_t json_size = 20ull + uint64_t(chunk0_length);
uint64_t header_and_json_size = 20ull + uint64_t(chunk0_length);
if (json_size > std::numeric_limits<uint32_t>::max()) {
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 ((json_size > uint64_t(size)) || (chunk0_length < 1) || (length > size) ||
(json_size > uint64_t(length)) ||
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) {
(*err) = "Invalid glTF binary.";
@@ -6287,61 +6326,77 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
// 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 ((json_size % 4) != 0) {
if ((header_and_json_size % 4) != 0) {
if (err) {
(*err) = "JSON Chunk end does not aligned to a 4-byte boundary.";
}
}
// Read Chunk1 info(BIN data)
if ((json_size + 8ull) > uint64_t(length)) {
if (err) {
(*err) = "Insufficient storage space for Chunk1(BIN data).";
//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 aligned 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;
}
return false;
}
unsigned int chunk1_length; // 4 bytes
unsigned int chunk1_format; // 4 bytes;
memcpy(&chunk1_length, bytes + json_size, 4); // JSON data length
swap4(&chunk1_length);
memcpy(&chunk1_format, bytes + json_size + 4, 4);
swap4(&chunk1_format);
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);
if (chunk1_length < 4) {
// TODO: Do we allow 0byte BIN data?
if (err) {
(*err) = "Insufficient Chunk1(BIN) data size.";
//std::cout << "chunk1_length = " << chunk1_length << "\n";
if (chunk1_length < 4) {
if (err) {
(*err) = "Insufficient Chunk1(BIN) data size.";
}
return false;
}
return false;
}
if ((chunk1_length % 4) != 0) {
if (err) {
(*err) = "BIN Chunk end does not aligned to a 4-byte boundary.";
if ((chunk1_length % 4) != 0) {
if (err) {
(*err) = "BIN Chunk end does not aligned to a 4-byte boundary.";
}
return false;
}
return false;
}
if (uint64_t(chunk1_length) + json_size > uint64_t(length)) {
if (err) {
(*err) = "BIN Chunk data length exceeds the GLB size.";
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;
}
return false;
}
if (chunk1_format != 0x004e4942) {
if (err) {
(*err) = "Invlid type for chunk1 data.";
if (chunk1_format != 0x004e4942) {
if (err) {
(*err) = "Invalid type for chunk1 data.";
}
return false;
}
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);
}
bin_data_ = bytes + json_size +
8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format)
bin_size_ = size_t(chunk1_length);
// Extract JSON string.
std::string jsonString(reinterpret_cast<const char *>(&bytes[20]),
chunk0_length);
@@ -6618,7 +6673,7 @@ static void SerializeGltfBufferData(const std::vector<unsigned char> &data,
SerializeStringProperty("uri", header + encodedData, o);
} else {
// Issue #229
// size 0 is allowd. Just emit mime header.
// size 0 is allowed. Just emit mime header.
SerializeStringProperty("uri", header, o);
}
}
@@ -6712,7 +6767,7 @@ static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) {
JsonAddMember(o, "extensions", std::move(extMap));
}
static void SerializeGltfAccessor(Accessor &accessor, json &o) {
static void SerializeGltfAccessor(const Accessor &accessor, json &o) {
if (accessor.bufferView >= 0)
SerializeNumberProperty<int>("bufferView", accessor.bufferView, o);
@@ -6804,7 +6859,8 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) {
}
}
static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
static void SerializeGltfAnimationChannel(const AnimationChannel &channel,
json &o) {
SerializeNumberProperty("sampler", channel.sampler, o);
{
json target;
@@ -6823,7 +6879,8 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) {
SerializeExtensionMap(channel.extensions, o);
}
static void SerializeGltfAnimationSampler(AnimationSampler &sampler, json &o) {
static void SerializeGltfAnimationSampler(const AnimationSampler &sampler,
json &o) {
SerializeNumberProperty("input", sampler.input, o);
SerializeNumberProperty("output", sampler.output, o);
SerializeStringProperty("interpolation", sampler.interpolation, o);
@@ -6833,7 +6890,7 @@ static void SerializeGltfAnimationSampler(AnimationSampler &sampler, json &o) {
}
}
static void SerializeGltfAnimation(Animation &animation, json &o) {
static void SerializeGltfAnimation(const Animation &animation, json &o) {
if (!animation.name.empty())
SerializeStringProperty("name", animation.name, o);
@@ -6869,7 +6926,7 @@ static void SerializeGltfAnimation(Animation &animation, json &o) {
SerializeExtensionMap(animation.extensions, o);
}
static void SerializeGltfAsset(Asset &asset, json &o) {
static void SerializeGltfAsset(const Asset &asset, json &o) {
if (!asset.generator.empty()) {
SerializeStringProperty("generator", asset.generator, o);
}
@@ -6878,14 +6935,15 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
SerializeStringProperty("copyright", asset.copyright, o);
}
if (asset.version.empty()) {
auto version = asset.version;
if (version.empty()) {
// Just in case
// `version` must be defined
asset.version = "2.0";
version = "2.0";
}
// TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0?
SerializeStringProperty("version", asset.version, o);
SerializeStringProperty("version", version, o);
if (asset.extras.Keys().size()) {
SerializeValue("extras", asset.extras, o);
@@ -6894,7 +6952,7 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
SerializeExtensionMap(asset.extensions, o);
}
static void SerializeGltfBufferBin(Buffer &buffer, json &o,
static void SerializeGltfBufferBin(const Buffer &buffer, json &o,
std::vector<unsigned char> &binBuffer) {
SerializeNumberProperty("byteLength", buffer.data.size(), o);
binBuffer = buffer.data;
@@ -6906,7 +6964,7 @@ static void SerializeGltfBufferBin(Buffer &buffer, json &o,
}
}
static void SerializeGltfBuffer(Buffer &buffer, json &o) {
static void SerializeGltfBuffer(const Buffer &buffer, json &o) {
SerializeNumberProperty("byteLength", buffer.data.size(), o);
SerializeGltfBufferData(buffer.data, o);
@@ -6917,7 +6975,7 @@ static void SerializeGltfBuffer(Buffer &buffer, json &o) {
}
}
static bool SerializeGltfBuffer(Buffer &buffer, json &o,
static bool SerializeGltfBuffer(const Buffer &buffer, json &o,
const std::string &binFilename,
const std::string &binBaseFilename) {
if (!SerializeGltfBufferData(buffer.data, binFilename)) return false;
@@ -6932,7 +6990,7 @@ static bool SerializeGltfBuffer(Buffer &buffer, json &o,
return true;
}
static void SerializeGltfBufferView(BufferView &bufferView, json &o) {
static void SerializeGltfBufferView(const BufferView &bufferView, json &o) {
SerializeNumberProperty("buffer", bufferView.buffer, o);
SerializeNumberProperty<size_t>("byteLength", bufferView.byteLength, o);
@@ -6958,14 +7016,16 @@ static void SerializeGltfBufferView(BufferView &bufferView, json &o) {
}
}
static void SerializeGltfImage(Image &image, json &o) {
// if uri empty, the mimeType and bufferview should be set
if (image.uri.empty()) {
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
if (uri.empty()) {
SerializeStringProperty("mimeType", image.mimeType, o);
SerializeNumberProperty<int>("bufferView", image.bufferView, o);
} else {
// TODO(syoyo): dlib::urilencode?
SerializeStringProperty("uri", image.uri, o);
SerializeStringProperty("uri", uri, o);
}
if (image.name.size()) {
@@ -6979,7 +7039,7 @@ static void SerializeGltfImage(Image &image, json &o) {
SerializeExtensionMap(image.extensions, o);
}
static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) {
static void SerializeGltfTextureInfo(const TextureInfo &texinfo, json &o) {
SerializeNumberProperty("index", texinfo.index, o);
if (texinfo.texCoord != 0) {
@@ -6993,7 +7053,7 @@ static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) {
SerializeExtensionMap(texinfo.extensions, o);
}
static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo,
static void SerializeGltfNormalTextureInfo(const NormalTextureInfo &texinfo,
json &o) {
SerializeNumberProperty("index", texinfo.index, o);
@@ -7012,8 +7072,8 @@ static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo,
SerializeExtensionMap(texinfo.extensions, o);
}
static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo,
json &o) {
static void SerializeGltfOcclusionTextureInfo(
const OcclusionTextureInfo &texinfo, json &o) {
SerializeNumberProperty("index", texinfo.index, o);
if (texinfo.texCoord != 0) {
@@ -7031,7 +7091,7 @@ static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo,
SerializeExtensionMap(texinfo.extensions, o);
}
static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr,
static void SerializeGltfPbrMetallicRoughness(const PbrMetallicRoughness &pbr,
json &o) {
std::vector<double> default_baseColorFactor = {1.0, 1.0, 1.0, 1.0};
if (!Equals(pbr.baseColorFactor, default_baseColorFactor)) {
@@ -7066,7 +7126,7 @@ static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr,
}
}
static void SerializeGltfMaterial(Material &material, json &o) {
static void SerializeGltfMaterial(const Material &material, json &o) {
if (material.name.size()) {
SerializeStringProperty("name", material.name, o);
}
@@ -7116,7 +7176,7 @@ static void SerializeGltfMaterial(Material &material, json &o) {
// Do not serialize `pbrMetallicRoughness` if pbrMetallicRoughness has all
// default values(json is null). Otherwise it will serialize to
// `pbrMetallicRoughness : null`, which cannot be read by other glTF
// importers(and validators).
// importers (and validators).
//
if (!JsonIsNull(pbrMetallicRoughness)) {
JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness));
@@ -7142,7 +7202,7 @@ static void SerializeGltfMaterial(Material &material, json &o) {
}
}
static void SerializeGltfMesh(Mesh &mesh, json &o) {
static void SerializeGltfMesh(const Mesh &mesh, json &o) {
json primitives;
JsonReserveArray(primitives, mesh.primitives.size());
for (unsigned int i = 0; i < mesh.primitives.size(); ++i) {
@@ -7158,7 +7218,7 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) {
JsonAddMember(primitive, "attributes", std::move(attributes));
}
// Indicies is optional
// Indices is optional
if (gltfPrimitive.indices > -1) {
SerializeNumberProperty<int>("indices", gltfPrimitive.indices, primitive);
}
@@ -7211,7 +7271,7 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) {
}
}
static void SerializeSpotLight(SpotLight &spot, json &o) {
static void SerializeSpotLight(const SpotLight &spot, json &o) {
SerializeNumberProperty("innerConeAngle", spot.innerConeAngle, o);
SerializeNumberProperty("outerConeAngle", spot.outerConeAngle, o);
SerializeExtensionMap(spot.extensions, o);
@@ -7220,7 +7280,7 @@ static void SerializeSpotLight(SpotLight &spot, json &o) {
}
}
static void SerializeGltfLight(Light &light, json &o) {
static void SerializeGltfLight(const Light &light, json &o) {
if (!light.name.empty()) SerializeStringProperty("name", light.name, o);
SerializeNumberProperty("intensity", light.intensity, o);
if (light.range > 0.0) {
@@ -7239,7 +7299,7 @@ static void SerializeGltfLight(Light &light, json &o) {
}
}
static void SerializeGltfNode(Node &node, json &o) {
static void SerializeGltfNode(const Node &node, json &o) {
if (node.translation.size() > 0) {
SerializeNumberArrayProperty<double>("translation", node.translation, o);
}
@@ -7277,7 +7337,7 @@ static void SerializeGltfNode(Node &node, json &o) {
SerializeNumberArrayProperty<int>("children", node.children, o);
}
static void SerializeGltfSampler(Sampler &sampler, json &o) {
static void SerializeGltfSampler(const Sampler &sampler, json &o) {
if (sampler.magFilter != -1) {
SerializeNumberProperty("magFilter", sampler.magFilter, o);
}
@@ -7346,7 +7406,7 @@ static void SerializeGltfCamera(const Camera &camera, json &o) {
SerializeExtensionMap(camera.extensions, o);
}
static void SerializeGltfScene(Scene &scene, json &o) {
static void SerializeGltfScene(const Scene &scene, json &o) {
SerializeNumberArrayProperty<int>("nodes", scene.nodes, o);
if (scene.name.size()) {
@@ -7358,7 +7418,7 @@ static void SerializeGltfScene(Scene &scene, json &o) {
SerializeExtensionMap(scene.extensions, o);
}
static void SerializeGltfSkin(Skin &skin, json &o) {
static void SerializeGltfSkin(const Skin &skin, json &o) {
// required
SerializeNumberArrayProperty<int>("joints", skin.joints, o);
@@ -7375,7 +7435,7 @@ static void SerializeGltfSkin(Skin &skin, json &o) {
}
}
static void SerializeGltfTexture(Texture &texture, json &o) {
static void SerializeGltfTexture(const Texture &texture, json &o) {
if (texture.sampler > -1) {
SerializeNumberProperty("sampler", texture.sampler, o);
}
@@ -7394,7 +7454,7 @@ static void SerializeGltfTexture(Texture &texture, json &o) {
///
/// Serialize all properties except buffers and images.
///
static void SerializeGltfModel(Model *model, json &o) {
static void SerializeGltfModel(const Model *model, json &o) {
// ACCESSORS
if (model->accessors.size()) {
json accessors;
@@ -7720,7 +7780,7 @@ static bool WriteBinaryGltfFile(const std::string &output,
return WriteBinaryGltfStream(gltfFile, content, binBuffer);
}
bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
bool TinyGLTF::WriteGltfSceneToStream(const Model *model, std::ostream &stream,
bool prettyPrint = true,
bool writeBinary = false) {
JsonDocument output;
@@ -7756,9 +7816,11 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
// UpdateImageObject need baseDir but only uses it if embeddedImages is
// 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, this->write_image_user_data_);
SerializeGltfImage(model->images[i], image);
&this->WriteImageData, &uri,
this->write_image_user_data_);
SerializeGltfImage(model->images[i], uri, image);
JsonPushBack(images, std::move(image));
}
JsonAddMember(output, "images", std::move(images));
@@ -7769,10 +7831,10 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream,
} else {
return WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1));
}
}
bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
bool TinyGLTF::WriteGltfSceneToFile(const Model *model,
const std::string &filename,
bool embedImages = false,
bool embedBuffers = false,
bool prettyPrint = true,
@@ -7845,9 +7907,11 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
for (unsigned int i = 0; i < model->images.size(); ++i) {
json image;
std::string uri;
UpdateImageObject(model->images[i], baseDir, int(i), embedImages,
&this->WriteImageData, this->write_image_user_data_);
SerializeGltfImage(model->images[i], image);
&this->WriteImageData, &uri,
this->write_image_user_data_);
SerializeGltfImage(model->images[i], uri, image);
JsonPushBack(images, std::move(image));
}
JsonAddMember(output, "images", std::move(images));
@@ -7858,7 +7922,6 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename,
} else {
return WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1)));
}
}
} // namespace tinygltf

11
wasm/Makefile Normal file
View File

@@ -0,0 +1,11 @@
WASI_VERSION=16
WASI_VERSION_FULL=${WASI_VERSION}.0
WASI_SDK_PATH=$(HOME)/local/wasi-sdk-${WASI_VERSION_FULL}
CC=${WASI_SDK_PATH}/bin/clang
CXX=${WASI_SDK_PATH}/bin/clang++
CXXFLAGS=-fno-rtti -fno-exceptions -g -Os
all:
$(CXX) ../loader_example.cc $(CXXFLAGS) -I../

31
wasm/README.md Normal file
View File

@@ -0,0 +1,31 @@
Experimental WASI/WASM build
## Build
Download wasi-sdk https://github.com/WebAssembly/wasi-sdk
Compile tinygltf with C++ exceptions and threads off. See `Makefile` for details
(NOTE: TinyGLTF itself does not use RTTI and threading feature(C++ threads, posix, win32 thread))
## Build examples and Run
Build `loader_example.cc`
```
$ /path/to/wasi-sdk-16.0/bin/clang++ ../loader_example.cc -fno-rtti -fno-exceptions -g -Os -I../ -o loader_example.wasi
```
Tested with wasmtime. https://github.com/bytecodealliance/wasmtime
Set a folder containing .gltf file to `--dir`
```
$ wasmtime --dir=../models loader_example.wasi ../models/Cube/Cube.gltf
```
## Emscripen
T.B.W. ...
EoL.