Merge branch 'master' into cmake-add-subdirectory

This commit is contained in:
Syoyo Fujita 2021-07-03 22:01:46 +09:00
commit f3dc4acaa4
8 changed files with 516 additions and 47 deletions

View File

@ -7,6 +7,7 @@ SET(CMAKE_CXX_STANDARD 11)
option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON) option(TINYGLTF_BUILD_LOADER_EXAMPLE "Build loader_example(load glTF and dump infos)" ON)
option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF) option(TINYGLTF_BUILD_GL_EXAMPLES "Build GL exampels(requires glfw, OpenGL, etc)" OFF)
option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF) option(TINYGLTF_BUILD_VALIDATOR_EXAMPLE "Build validator exampe" OFF)
option(TINYGLTF_BUILD_BUILDER_EXAMPLE "Build glTF builder example" OFF)
option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF) option(TINYGLTF_HEADER_ONLY "On: header-only mode. Off: create tinygltf library(No TINYGLTF_IMPLEMENTATION required in your project)" OFF)
option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON) option(TINYGLTF_INSTALL "Install tinygltf files during install step. Usually set to OFF if you include tinygltf through add_subdirectory()" ON)
@ -25,12 +26,16 @@ if (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
ADD_SUBDIRECTORY ( examples/validator ) ADD_SUBDIRECTORY ( examples/validator )
endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE) endif (TINYGLTF_BUILD_VALIDATOR_EXAMPLE)
if (TINYGLTF_BUILD_BUILDER_EXAMPLE)
ADD_SUBDIRECTORY ( examples/build-gltf )
endif (TINYGLTF_BUILD_BUILDER_EXAMPLE)
# #
# for add_subdirectory and standalone build # for add_subdirectory and standalone build
# #
if (TINYGLTF_HEADER_ONLY) if (TINYGLTF_HEADER_ONLY)
add_library(tinygltf INTERFACE) add_library(tinygltf INTERFACE)
target_include_directories(tinygltf target_include_directories(tinygltf
INTERFACE INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@ -61,7 +66,7 @@ if (TINYGLTF_INSTALL)
DESTINATION DESTINATION
include include
) )
INSTALL ( FILES INSTALL ( FILES
cmake/TinyGLTFConfig.cmake cmake/TinyGLTFConfig.cmake
DESTINATION DESTINATION

View File

@ -77,6 +77,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [glview](examples/glview) : Simple glTF geometry viewer. * [glview](examples/glview) : Simple glTF geometry viewer.
* [validator](examples/validator) : Simple glTF validator with JSON schema. * [validator](examples/validator) : Simple glTF validator with JSON schema.
* [basic](examples/basic) : Basic glTF viewer with texturing support. * [basic](examples/basic) : Basic glTF viewer with texturing support.
* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch.
## Projects using TinyGLTF ## Projects using TinyGLTF
@ -90,6 +91,7 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux * [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux
* [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications. * [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications.
* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11 * [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
* Your projects here! (Please send PR) * Your projects here! (Please send PR)
## TODOs ## TODOs
@ -168,6 +170,7 @@ if (!ret) {
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand. * `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file. * `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_RAPIDJSON `: Disable including RapidJson's header files from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this featrure. * `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this featrure.

View File

@ -0,0 +1,2 @@
all:
$(CXX) -o create_triangle_gltf -I../../ create_triangle_gltf.cpp

View File

@ -0,0 +1,121 @@
// An example of how to generate a gltf file from scratch. This example
// was translated from the pygltlib documentation in the pypi project page,
// which in turn is based on the Khronos Sample Models at:
//
// https://github.com/KhronosGroup/glTF-Sample-Models
//
// This example is released under the MIT license.
//
// 2021-02-25 Thu
// Dov Grobgeld <dov.grobgeld@gmail.com>
// Define these only in *one* .cc file.
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
// #define TINYGLTF_NOEXCEPTION // optional. disable exception handling.
#include "tiny_gltf.h"
int main(int argc, char **argv)
{
// Create a model with a single mesh and save it as a gltf file
tinygltf::Model m;
tinygltf::Scene scene;
tinygltf::Mesh mesh;
tinygltf::Primitive primitive;
tinygltf::Node node;
tinygltf::Buffer buffer;
tinygltf::BufferView bufferView1;
tinygltf::BufferView bufferView2;
tinygltf::Accessor accessor1;
tinygltf::Accessor accessor2;
tinygltf::Asset asset;
// This is the raw data buffer.
buffer.data = {
// 6 bytes of indices and two bytes of padding
0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,
// 36 bytes of floating point numbers
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,
0x00,0x00,0x00,0x00};
// "The indices of the vertices (ELEMENT_ARRAY_BUFFER) take up 6 bytes in the
// start of the buffer.
bufferView1.buffer = 0;
bufferView1.byteOffset=0;
bufferView1.byteLength=6;
bufferView1.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
// The vertices take up 36 bytes (3 vertices * 3 floating points * 4 bytes)
// at position 8 in the buffer and are of type ARRAY_BUFFER
bufferView2.buffer = 0;
bufferView2.byteOffset=8;
bufferView2.byteLength=36;
bufferView2.target = TINYGLTF_TARGET_ARRAY_BUFFER;
// Describe the layout of bufferView1, the indices of the vertices
accessor1.bufferView = 0;
accessor1.byteOffset = 0;
accessor1.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
accessor1.count = 3;
accessor1.type = TINYGLTF_TYPE_SCALAR;
accessor1.maxValues.push_back(2);
accessor1.minValues.push_back(0);
// Describe the layout of bufferView2, the vertices themself
accessor2.bufferView = 1;
accessor2.byteOffset = 0;
accessor2.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
accessor2.count = 3;
accessor2.type = TINYGLTF_TYPE_VEC3;
accessor2.maxValues = {1.0, 1.0, 0.0};
accessor2.minValues = {0.0, 0.0, 0.0};
// Build the mesh primitive and add it to the mesh
primitive.indices = 0; // The index of the accessor for the vertex indices
primitive.attributes["POSITION"] = 1; // The index of the accessor for positions
primitive.material = 0;
primitive.mode = TINYGLTF_MODE_TRIANGLES;
mesh.primitives.push_back(primitive);
// Other tie ups
node.mesh = 0;
scene.nodes.push_back(0); // Default scene
// Define the asset. The version is required
asset.version = "2.0";
asset.generator = "tinygltf";
// Now all that remains is to tie back all the loose objects into the
// our single model.
m.scenes.push_back(scene);
m.meshes.push_back(mesh);
m.nodes.push_back(node);
m.buffers.push_back(buffer);
m.bufferViews.push_back(bufferView1);
m.bufferViews.push_back(bufferView2);
m.accessors.push_back(accessor1);
m.accessors.push_back(accessor2);
m.asset = asset;
// Create a simple material
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
mat.doubleSided = true;
m.materials.push_back(mat);
// Save it to a file
tinygltf::TinyGLTF gltf;
gltf.WriteGltfSceneToFile(&m, "triangle.gltf",
true, // embedImages
true, // embedBuffers
true, // pretty print
false); // write binary
exit(0);
}

View File

@ -29,7 +29,7 @@ if (DEFINED DRACO_DIR)
# TODO(syoyo): better CMake script for draco # TODO(syoyo): better CMake script for draco
add_definitions(-DTINYGLTF_ENABLE_DRACO) add_definitions(-DTINYGLTF_ENABLE_DRACO)
include_directories(${DRACO_DIR}/include) include_directories(${DRACO_DIR}/include)
link_directories(${DRACO_DIR}/lib) link_directories(${DRACO_DIR}/lib)
set(DRACO_LIBRARY draco) set(DRACO_LIBRARY draco)
endif () endif ()
@ -49,9 +49,9 @@ add_executable(glview
) )
target_link_libraries ( glview target_link_libraries ( glview
${DRACO_LIBRARY} ${DRACO_LIBRARY}
${GLFW3_UNIX_LINK_LIBRARIES} ${GLFW3_UNIX_LINK_LIBRARIES}
${GLEW_LIBRARY} ${GLEW_LIBRARIES}
${GLFW3_glfw_LIBRARY} ${GLFW3_glfw_LIBRARY}
${OPENGL_gl_LIBRARY} ${OPENGL_gl_LIBRARY}
${OPENGL_glu_LIBRARY} ${OPENGL_glu_LIBRARY}

File diff suppressed because one or more lines are too long

View File

@ -432,11 +432,40 @@ TEST_CASE("serialize-empty-material", "[issue-294]") {
nlohmann::json j = nlohmann::json::parse(os.str()); nlohmann::json j = nlohmann::json::parse(os.str());
REQUIRE(1 == j["materials"].size()); REQUIRE(1 == j["materials"].size());
REQUIRE(j["asset"].is_null());
REQUIRE(j["materials"][0].is_object()); REQUIRE(j["materials"][0].is_object());
} }
TEST_CASE("empty-skeleton-id", "[issue-321]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
bool ret = ctx.LoadASCIIFromFile(&model, &err, &warn, "../models/regression/unassigned-skeleton.gltf");
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(model.skins.size() == 1);
REQUIRE(model.skins[0].skeleton == -1); // unassigned
std::stringstream os;
ctx.WriteGltfSceneToStream(&model, os, false, false);
// use nlohmann json
nlohmann::json j = nlohmann::json::parse(os.str());
// Ensure `skeleton` property is not written to .gltf(was serialized as -1)
REQUIRE(1 == j["skins"].size());
REQUIRE(j["skins"][0].is_object());
REQUIRE(j["skins"][0].count("skeleton") == 0);
}
#ifndef TINYGLTF_NO_FS #ifndef TINYGLTF_NO_FS
TEST_CASE("expandpath-utf-8", "[pr-226]") { TEST_CASE("expandpath-utf-8", "[pr-226]") {

View File

@ -4,7 +4,7 @@
// //
// The MIT License (MIT) // The MIT License (MIT)
// //
// Copyright (c) 2015 - 2020 Syoyo Fujita, Aurélien Chatelain and many // Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many
// contributors. // contributors.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
@ -27,7 +27,8 @@
// Version: // Version:
// - v2.5.0 Add SetPreserveImageChannels() option to load image data as is. // - v2.5.0 Add SetPreserveImageChannels() option to load image data as is.
// - v2.4.3 Fix null object output when when material has all default parameters. // - v2.4.3 Fix null object output when when material has all default
// parameters.
// - v2.4.2 Decode percent-encoded URI. // - v2.4.2 Decode percent-encoded URI.
// - v2.4.1 Fix some glTF object class does not have `extensions` and/or // - v2.4.1 Fix some glTF object class does not have `extensions` and/or
// `extras` property. // `extras` property.
@ -190,14 +191,14 @@ AAssetManager *asset_manager = nullptr;
#endif #endif
typedef enum { typedef enum {
NULL_TYPE = 0, NULL_TYPE,
REAL_TYPE = 1, REAL_TYPE,
INT_TYPE = 2, INT_TYPE,
BOOL_TYPE = 3, BOOL_TYPE,
STRING_TYPE = 4, STRING_TYPE,
ARRAY_TYPE = 5, ARRAY_TYPE,
BINARY_TYPE = 6, BINARY_TYPE,
OBJECT_TYPE = 7 OBJECT_TYPE
} Type; } Type;
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) { static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
@ -297,7 +298,7 @@ class Value {
DEFAULT_METHODS(Value) DEFAULT_METHODS(Value)
char Type() const { return static_cast<const char>(type_); } char Type() const { return static_cast<char>(type_); }
bool IsBool() const { return (type_ == BOOL_TYPE); } bool IsBool() const { return (type_ == BOOL_TYPE); }
@ -603,7 +604,7 @@ struct Sampler {
// `magFilter`. Set -1 in TinyGLTF(issue #186) // `magFilter`. Set -1 in TinyGLTF(issue #186)
int minFilter = int minFilter =
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR", -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST", // "NEAREST_MIPMAP_NEAREST", "LINEAR_MIPMAP_NEAREST",
// "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"] // "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
int magFilter = int magFilter =
-1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"] -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
@ -849,8 +850,10 @@ struct Accessor {
std::string extras_json_string; std::string extras_json_string;
std::string extensions_json_string; std::string extensions_json_string;
std::vector<double> minValues; // optional std::vector<double>
std::vector<double> maxValues; // optional minValues; // optional. integer value is promoted to double
std::vector<double>
maxValues; // optional. integer value is promoted to double
struct { struct {
int count; int count;
@ -1068,7 +1071,7 @@ struct Buffer {
}; };
struct Asset { struct Asset {
std::string version; // required std::string version = "2.0"; // required
std::string generator; std::string generator;
std::string minVersion; std::string minVersion;
std::string copyright; std::string copyright;
@ -1190,7 +1193,8 @@ enum SectionCheck {
/// ///
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
std::string *, int, int, std::string *, int, int,
const unsigned char *, int, void *user_pointer); const unsigned char *, int,
void *user_pointer);
/// ///
/// WriteImageDataFunction type. Signature for custom image writing callbacks. /// WriteImageDataFunction type. Signature for custom image writing callbacks.
@ -1397,9 +1401,7 @@ class TinyGLTF {
preserve_image_channels_ = onoff; preserve_image_channels_ = onoff;
} }
bool GetPreserveImageChannels() const { bool GetPreserveImageChannels() const { return preserve_image_channels_; }
return preserve_image_channels_;
}
private: private:
/// ///
@ -1420,7 +1422,8 @@ class TinyGLTF {
bool store_original_json_for_extras_and_extensions_ = false; bool store_original_json_for_extras_and_extensions_ = false;
bool preserve_image_channels_ = false; /// Default false(expand channels to RGBA) for backward compatibility. bool preserve_image_channels_ = false; /// Default false(expand channels to
/// RGBA) for backward compatibility.
FsCallbacks fs = { FsCallbacks fs = {
#ifndef TINYGLTF_NO_FS #ifndef TINYGLTF_NO_FS
@ -1535,6 +1538,7 @@ class TinyGLTF {
#ifndef TINYGLTF_USE_RAPIDJSON #ifndef TINYGLTF_USE_RAPIDJSON
#include "json.hpp" #include "json.hpp"
#else #else
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
#include "document.h" #include "document.h"
#include "prettywriter.h" #include "prettywriter.h"
#include "rapidjson.h" #include "rapidjson.h"
@ -1542,6 +1546,7 @@ class TinyGLTF {
#include "writer.h" #include "writer.h"
#endif #endif
#endif #endif
#endif
#ifdef TINYGLTF_ENABLE_DRACO #ifdef TINYGLTF_ENABLE_DRACO
#include "draco/compression/decode.h" #include "draco/compression/decode.h"
@ -1707,14 +1712,14 @@ namespace tinygltf {
/// ///
/// Internal LoadImageDataOption struct. /// Internal LoadImageDataOption struct.
/// This struct is passed through `user_pointer` in LoadImageData. /// This struct is passed through `user_pointer` in LoadImageData.
/// The struct is not passed when the user supply their own LoadImageData callbacks. /// The struct is not passed when the user supply their own LoadImageData
/// callbacks.
/// ///
struct LoadImageDataOption struct LoadImageDataOption {
{ // true: preserve image channels(e.g. load as RGB image if the image has RGB
// true: preserve image channels(e.g. load as RGB image if the image has RGB channels) // channels) default `false`(channels are expanded to RGBA for backward
// default `false`(channels are expanded to RGBA for backward compatiblity). // compatiblity).
bool preserve_channels{false}; bool preserve_channels{false};
}; };
// Equals function for Value, for recursivity // Equals function for Value, for recursivity
@ -2363,8 +2368,8 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err,
unsigned char *data = nullptr; unsigned char *data = nullptr;
// preserve_channels true: Use channels stored in the image file. // preserve_channels true: Use channels stored in the image file.
// false: force 32-bit textures for common Vulkan compatibility. It appears that // false: force 32-bit textures for common Vulkan compatibility. It appears
// some GPU drivers do not support 24-bit images for Vulkan // that some GPU drivers do not support 24-bit images for Vulkan
req_comp = option.preserve_channels ? 0 : 4; req_comp = option.preserve_channels ? 0 : 4;
int bits = 8; int bits = 8;
int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
@ -4467,6 +4472,7 @@ static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh,
static bool ParseDracoExtension(Primitive *primitive, Model *model, static bool ParseDracoExtension(Primitive *primitive, Model *model,
std::string *err, std::string *err,
const Value &dracoExtensionValue) { const Value &dracoExtensionValue) {
(void)err;
auto bufferViewValue = dracoExtensionValue.Get("bufferView"); auto bufferViewValue = dracoExtensionValue.Get("bufferView");
if (!bufferViewValue.IsInt()) return false; if (!bufferViewValue.IsInt()) return false;
auto attributesValue = dracoExtensionValue.Get("attributes"); auto attributesValue = dracoExtensionValue.Get("attributes");
@ -4527,7 +4533,6 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
int dracoAttributeIndex = attribute.second.Get<int>(); int dracoAttributeIndex = attribute.second.Get<int>();
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex); const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
const auto pBuffer = pAttribute->buffer();
const auto componentType = const auto componentType =
model->accessors[primitiveAttribute->second].componentType; model->accessors[primitiveAttribute->second].componentType;
@ -5827,13 +5832,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
{ {
json_const_iterator it; json_const_iterator it;
if (FindMember(o, "extensions", it)) { if (FindMember(o, "extensions", it)) {
model->extensions_json_string = JsonToString(GetValue(it)); scene.extensions_json_string = JsonToString(GetValue(it));
} }
} }
{ {
json_const_iterator it; json_const_iterator it;
if (FindMember(o, "extras", it)) { if (FindMember(o, "extras", it)) {
model->extras_json_string = JsonToString(GetValue(it)); scene.extras_json_string = JsonToString(GetValue(it));
} }
} }
} }
@ -6621,8 +6626,33 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) {
SerializeNumberProperty<int>("componentType", accessor.componentType, o); SerializeNumberProperty<int>("componentType", accessor.componentType, o);
SerializeNumberProperty<size_t>("count", accessor.count, o); SerializeNumberProperty<size_t>("count", accessor.count, o);
SerializeNumberArrayProperty<double>("min", accessor.minValues, o);
SerializeNumberArrayProperty<double>("max", accessor.maxValues, o); if ((accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) ||
(accessor.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)) {
SerializeNumberArrayProperty<double>("min", accessor.minValues, o);
SerializeNumberArrayProperty<double>("max", accessor.maxValues, o);
} else {
// Issue #301. Serialize as integer.
// Assume int value is within [-2**31-1, 2**31-1]
{
std::vector<int> values;
std::transform(accessor.minValues.begin(), accessor.minValues.end(),
std::back_inserter(values),
[](double v) { return static_cast<int>(v); });
SerializeNumberArrayProperty<int>("min", values, o);
}
{
std::vector<int> values;
std::transform(accessor.maxValues.begin(), accessor.maxValues.end(),
std::back_inserter(values),
[](double v) { return static_cast<int>(v); });
SerializeNumberArrayProperty<int>("max", values, o);
}
}
if (accessor.normalized) if (accessor.normalized)
SerializeValue("normalized", Value(accessor.normalized), o); SerializeValue("normalized", Value(accessor.normalized), o);
std::string type; std::string type;
@ -6732,10 +6762,15 @@ static void SerializeGltfAsset(Asset &asset, json &o) {
SerializeStringProperty("copyright", asset.copyright, o); SerializeStringProperty("copyright", asset.copyright, o);
} }
if (!asset.version.empty()) { if (asset.version.empty()) {
SerializeStringProperty("version", asset.version, o); // Just in case
// `version` must be defined
asset.version = "2.0";
} }
// TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0?
SerializeStringProperty("version", asset.version, o);
if (asset.extras.Keys().size()) { if (asset.extras.Keys().size()) {
SerializeValue("extras", asset.extras, o); SerializeValue("extras", asset.extras, o);
} }
@ -7208,11 +7243,17 @@ static void SerializeGltfScene(Scene &scene, json &o) {
} }
static void SerializeGltfSkin(Skin &skin, json &o) { static void SerializeGltfSkin(Skin &skin, json &o) {
if (skin.inverseBindMatrices != -1) // required
SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o);
SerializeNumberArrayProperty<int>("joints", skin.joints, o); SerializeNumberArrayProperty<int>("joints", skin.joints, o);
SerializeNumberProperty("skeleton", skin.skeleton, o);
if (skin.inverseBindMatrices >= 0) {
SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o);
}
if (skin.skeleton >= 0) {
SerializeNumberProperty("skeleton", skin.skeleton, o);
}
if (skin.name.size()) { if (skin.name.size()) {
SerializeStringProperty("name", skin.name, o); SerializeStringProperty("name", skin.name, o);
} }
@ -7299,7 +7340,8 @@ static void SerializeGltfModel(Model *model, json &o) {
if (JsonIsNull(material)) { if (JsonIsNull(material)) {
// Issue 294. // Issue 294.
// `material` does not have any required parameters // `material` does not have any required parameters
// so the result may be null(unmodified) when all material parameters have default value. // so the result may be null(unmodified) when all material parameters
// have default value.
// //
// null is not allowed thus we create an empty JSON object. // null is not allowed thus we create an empty JSON object.
JsonSetObject(material); JsonSetObject(material);
@ -7442,7 +7484,7 @@ static void SerializeGltfModel(Model *model, json &o) {
} }
// Extensions used // Extensions used
if (model->extensionsUsed.size()) { if (extensionsUsed.size()) {
SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o); SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o);
} }