From 6e08b17ce3ea37a40d5e17f33b70339aa86f6326 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Wed, 30 Oct 2019 17:25:38 +0900 Subject: [PATCH] Add feature to store original JSON string for extras and extensions(for user-specific JSON parsing). # Fixes 215 Fix some glTF object(e.g. Skin) does not have extras and/or extensions property. --- loader_example.cc | 174 +++++++++- tiny_gltf.h | 791 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 863 insertions(+), 102 deletions(-) diff --git a/loader_example.cc b/loader_example.cc index 93a6866..dbe10ad 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -322,6 +322,15 @@ static void DumpStringIntMap(const std::map &m, int indent) { } } +static void DumpExtensions(const tinygltf::ExtensionMap &extension, + const int indent) { + // TODO(syoyo): pritty print Value + for (auto &e : extension) { + std::cout << Indent(indent) << e.first << std::endl; + std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl; + } +} + static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) { std::cout << Indent(indent) << "material : " << primitive.material << std::endl; @@ -333,19 +342,23 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) { << std::endl; DumpStringIntMap(primitive.attributes, indent + 1); + DumpExtensions(primitive.extensions, indent); std::cout << Indent(indent) << "extras :" << std::endl << PrintValue("extras", primitive.extras, indent + 1) << std::endl; -} -static void DumpExtensions(const tinygltf::ExtensionMap &extension, - const int indent) { - // TODO(syoyo): pritty print Value - for (auto &e : extension) { - std::cout << Indent(indent) << e.first << std::endl; - std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl; + if (!primitive.extensions_json_string.empty()) { + std::cout << Indent(indent + 1) << "extensions(JSON string) = " + << primitive.extensions_json_string << "\n"; + } + + if (!primitive.extras_json_string.empty()) { + std::cout << Indent(indent + 1) + << "extras(JSON string) = " << primitive.extras_json_string + << "\n"; } } + static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo, const int indent) { std::cout << Indent(indent) << "index : " << texinfo.index << "\n"; @@ -353,6 +366,17 @@ static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo, << "\n"; DumpExtensions(texinfo.extensions, indent + 1); std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n"; + + if (!texinfo.extensions_json_string.empty()) { + std::cout << Indent(indent) + << "extensions(JSON string) = " << texinfo.extensions_json_string + << "\n"; + } + + if (!texinfo.extras_json_string.empty()) { + std::cout << Indent(indent) + << "extras(JSON string) = " << texinfo.extras_json_string << "\n"; + } } static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo, @@ -546,6 +570,21 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(2) << "target : " << PrintTarget(bufferView.target) << std::endl; + std::cout << Indent(1) << "-------------------------------------\n"; + + DumpExtensions(bufferView.extensions, 1); + std::cout << PrintValue("extras", bufferView.extras, 2) << std::endl; + + if (!bufferView.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << bufferView.extensions_json_string << "\n"; + } + + if (!bufferView.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << bufferView.extras_json_string + << "\n"; + } } } @@ -556,6 +595,21 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(1) << "name : " << buffer.name << std::endl; std::cout << Indent(2) << "byteLength : " << buffer.data.size() << std::endl; + std::cout << Indent(1) << "-------------------------------------\n"; + + DumpExtensions(buffer.extensions, 1); + std::cout << PrintValue("extras", buffer.extras, 2) << std::endl; + + if (!buffer.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << buffer.extensions_json_string << "\n"; + } + + if (!buffer.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << buffer.extras_json_string + << "\n"; + } } } @@ -602,6 +656,17 @@ static void Dump(const tinygltf::Model &model) { DumpExtensions(material.extensions, 1); std::cout << PrintValue("extras", material.extras, 2) << std::endl; + + if (!material.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << material.extensions_json_string << "\n"; + } + + if (!material.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << material.extras_json_string + << "\n"; + } } } @@ -625,6 +690,18 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(2) << "height : " << image.height << std::endl; std::cout << Indent(2) << "component : " << image.component << std::endl; DumpExtensions(image.extensions, 1); + std::cout << PrintValue("extras", image.extras, 2) << std::endl; + + if (!image.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << image.extensions_json_string << "\n"; + } + + if (!image.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << image.extras_json_string + << "\n"; + } } } @@ -637,6 +714,18 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(1) << "source : " << texture.source << std::endl; DumpExtensions(texture.extensions, 1); + std::cout << PrintValue("extras", texture.extras, 2) << std::endl; + + if (!texture.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << texture.extensions_json_string << "\n"; + } + + if (!texture.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << texture.extras_json_string + << "\n"; + } } } @@ -658,6 +747,20 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(2) << "wrapT : " << PrintWrapMode(sampler.wrapT) << std::endl; + + DumpExtensions(sampler.extensions, 1); + std::cout << PrintValue("extras", sampler.extras, 2) << std::endl; + + if (!sampler.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << sampler.extensions_json_string << "\n"; + } + + if (!sampler.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << sampler.extras_json_string + << "\n"; + } } } @@ -690,6 +793,54 @@ static void Dump(const tinygltf::Model &model) { << "znear : " << camera.orthographic.znear << std::endl; } + + std::cout << Indent(1) << "-------------------------------------\n"; + + DumpExtensions(camera.extensions, 1); + std::cout << PrintValue("extras", camera.extras, 2) << std::endl; + + if (!camera.extensions_json_string.empty()) { + std::cout << Indent(2) << "extensions(JSON string) = " + << camera.extensions_json_string << "\n"; + } + + if (!camera.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << camera.extras_json_string + << "\n"; + } + } + } + + { + std::cout << "skins(items=" << model.skins.size() << ")" << std::endl; + for (size_t i = 0; i < model.skins.size(); i++) { + const tinygltf::Skin &skin = model.skins[i]; + std::cout << Indent(1) << "name : " << skin.name << std::endl; + std::cout << Indent(2) + << "inverseBindMatrices : " << skin.inverseBindMatrices + << std::endl; + std::cout << Indent(2) << "skeleton : " << skin.skeleton + << std::endl; + std::cout << Indent(2) + << "joints : " << PrintIntArray(skin.joints) + << std::endl; + std::cout << Indent(1) << "-------------------------------------\n"; + + DumpExtensions(skin.extensions, 1); + std::cout << PrintValue("extras", skin.extras, 2) << std::endl; + + if (!skin.extensions_json_string.empty()) { + std::cout << Indent(2) + << "extensions(JSON string) = " << skin.extensions_json_string + << "\n"; + } + + if (!skin.extras_json_string.empty()) { + std::cout << Indent(2) + << "extras(JSON string) = " << skin.extras_json_string + << "\n"; + } } } @@ -707,6 +858,12 @@ int main(int argc, char **argv) { exit(1); } + // Store original JSON string for `extras` and `extensions` + bool store_original_json_for_extras_and_extensions = false; + if (argc > 2) { + store_original_json_for_extras_and_extensions = true; + } + tinygltf::Model model; tinygltf::TinyGLTF gltf_ctx; std::string err; @@ -714,6 +871,9 @@ int main(int argc, char **argv) { std::string input_filename(argv[1]); std::string ext = GetFilePathExtension(input_filename); + gltf_ctx.SetStoreOriginalJSONForExtrasAndExtensions( + store_original_json_for_extras_and_extensions); + bool ret = false; if (ext.compare("glb") == 0) { std::cout << "Reading binary glTF" << std::endl; diff --git a/tiny_gltf.h b/tiny_gltf.h index 23b16c9..dea02e7 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -26,6 +26,8 @@ // THE SOFTWARE. // Version: +// - v2.4.1 Fix some glTF object class does not have `extensions` and/or +// `extras` property. // - v2.4.0 Experimental RapidJSON and C++14 support(Thanks to @jrkoone). // - v2.3.1 Set default value of minFilter and magFilter in Sampler to -1. // - v2.3.0 Modified Material representation according to glTF 2.0 schema @@ -77,12 +79,12 @@ #define TINYGLTF_NOEXCEPT noexcept #endif -#define DEFAULT_METHODS(x) \ - ~x() = default; \ - x(const x&) = default; \ - x(x&&) TINYGLTF_NOEXCEPT = default; \ - x& operator=(const x&) = default; \ - x& operator=(x&&) TINYGLTF_NOEXCEPT = default; +#define DEFAULT_METHODS(x) \ + ~x() = default; \ + x(const x &) = default; \ + x(x &&) TINYGLTF_NOEXCEPT = default; \ + x &operator=(const x &) = default; \ + x &operator=(x &&) TINYGLTF_NOEXCEPT = default; namespace tinygltf { @@ -525,6 +527,10 @@ struct AnimationChannel { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + AnimationChannel() : sampler(-1), target_node(-1) {} DEFAULT_METHODS(AnimationChannel) bool operator==(const AnimationChannel &) const; @@ -536,6 +542,11 @@ struct AnimationSampler { std::string interpolation; // "LINEAR", "STEP","CUBICSPLINE" or user defined // string. default "LINEAR" Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {} DEFAULT_METHODS(AnimationSampler) @@ -549,6 +560,10 @@ struct Animation { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Animation() = default; DEFAULT_METHODS(Animation) bool operator==(const Animation &) const; @@ -560,6 +575,13 @@ struct Skin { int skeleton; // The index of the node used as a skeleton root std::vector joints; // Indices of skeleton nodes + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Skin() { inverseBindMatrices = -1; skeleton = -1; @@ -585,7 +607,13 @@ struct Sampler { TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", // "REPEAT"], default "REPEAT" int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; Sampler() : minFilter(-1), @@ -613,6 +641,10 @@ struct Image { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg // compressed for "image/jpeg" mime) This feature is good if you use custom // image loader function. (e.g. delayed decoding of images for faster glTF @@ -640,6 +672,10 @@ struct Texture { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Texture() : sampler(-1), source(-1) {} DEFAULT_METHODS(Texture) @@ -654,6 +690,10 @@ struct TextureInfo { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + TextureInfo() : index(-1), texCoord(0) {} DEFAULT_METHODS(TextureInfo) bool operator==(const TextureInfo &) const; @@ -669,6 +709,10 @@ struct NormalTextureInfo { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + NormalTextureInfo() : index(-1), texCoord(0), scale(1.0) {} DEFAULT_METHODS(NormalTextureInfo) bool operator==(const NormalTextureInfo &) const; @@ -684,6 +728,10 @@ struct OcclusionTextureInfo { Value extras; ExtensionMap extensions; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + OcclusionTextureInfo() : index(-1), texCoord(0), strength(1.0) {} DEFAULT_METHODS(OcclusionTextureInfo) bool operator==(const OcclusionTextureInfo &) const; @@ -700,7 +748,14 @@ struct PbrMetallicRoughness { Value extras; ExtensionMap extensions; - PbrMetallicRoughness() : baseColorFactor(std::vector{ 1.0,1.0,1.0,1.0 }), metallicFactor(1.0), roughnessFactor(1.0) {} + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + PbrMetallicRoughness() + : baseColorFactor(std::vector{1.0, 1.0, 1.0, 1.0}), + metallicFactor(1.0), + roughnessFactor(1.0) {} DEFAULT_METHODS(PbrMetallicRoughness) bool operator==(const PbrMetallicRoughness &) const; }; @@ -730,6 +785,10 @@ struct Material { ExtensionMap extensions; Value extras; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Material() : alphaMode("OPAQUE"), alphaCutoff(0.5), doubleSided(false) {} DEFAULT_METHODS(Material) @@ -745,6 +804,12 @@ struct BufferView { // understood to be tightly packed int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + bool dracoDecoded; // Flag indicating this has been draco decoded BufferView() : byteOffset(0), byteStride(0), dracoDecoded(false) {} @@ -762,6 +827,11 @@ struct Accessor { size_t count; // required int type; // (required) One of TINYGLTF_TYPE_*** .. Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; std::vector minValues; // optional std::vector maxValues; // optional @@ -842,6 +912,10 @@ struct PerspectiveCamera { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; struct OrthographicCamera { @@ -856,6 +930,10 @@ struct OrthographicCamera { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; struct Camera { @@ -871,6 +949,10 @@ struct Camera { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; struct Primitive { @@ -889,6 +971,10 @@ struct Primitive { ExtensionMap extensions; Value extras; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Primitive() { material = -1; indices = -1; @@ -904,6 +990,10 @@ struct Mesh { ExtensionMap extensions; Value extras; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Mesh() = default; DEFAULT_METHODS(Mesh) bool operator==(const Mesh &) const; @@ -931,6 +1021,10 @@ class Node { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; struct Buffer { @@ -939,6 +1033,11 @@ struct Buffer { std::string uri; // considered as required here but not in the spec (need to clarify) Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; Buffer() = default; DEFAULT_METHODS(Buffer) @@ -953,6 +1052,10 @@ struct Asset { ExtensionMap extensions; Value extras; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Asset() = default; DEFAULT_METHODS(Asset) bool operator==(const Asset &) const; @@ -965,6 +1068,10 @@ struct Scene { ExtensionMap extensions; Value extras; + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + Scene() = default; DEFAULT_METHODS(Scene) bool operator==(const Scene &) const; @@ -980,6 +1087,10 @@ struct SpotLight { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; struct Light { @@ -997,6 +1108,10 @@ struct Light { ExtensionMap extensions; Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; class Model { @@ -1020,7 +1135,6 @@ class Model { std::vector cameras; std::vector scenes; std::vector lights; - ExtensionMap extensions; int defaultScene; std::vector extensionsUsed; @@ -1029,6 +1143,11 @@ class Model { Asset asset; Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; }; enum SectionCheck { @@ -1222,6 +1341,19 @@ class TinyGLTF { bool GetSerializeDefaultValues() const { return serialize_default_values_; } + /// + /// Store original JSON string for `extras` and `extensions`. + /// This feature will be useful when the user want to reconstruct custom data + /// structure from JSON string. + /// + void SetStoreOriginalJSONForExtrasAndExtensions(const bool enabled) { + store_original_json_for_extras_and_extensions_ = enabled; + } + + bool GetStoreOriginalJSONForExtrasAndExtensions() const { + return store_original_json_for_extras_and_extensions_; + } + private: /// /// Loads glTF asset from string(memory). @@ -1239,6 +1371,8 @@ class TinyGLTF { bool serialize_default_values_ = false; ///< Serialize default values? + bool store_original_json_for_extras_and_extensions_ = false; + FsCallbacks fs = { #ifndef TINYGLTF_NO_FS &tinygltf::FileExists, &tinygltf::ExpandFilePath, @@ -1293,7 +1427,9 @@ class TinyGLTF { #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wglobal-constructors" +#if __has_warning("-Wreserved-id-macro") #pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" #pragma clang diagnostic ignored "-Wpadded" #pragma clang diagnostic ignored "-Wc++98-compat" @@ -1443,6 +1579,13 @@ rapidjson::Document::AllocatorType &GetAllocator() { assert(s_pActiveDocument); // Root json node must be JsonDocument type return s_pActiveDocument->GetAllocator(); } + +#ifdef __clang__ +#pragma clang diagnostic push +// Suppress JsonDocument(JsonDocument &&rhs) noexcept +#pragma clang diagnostic ignored "-Wunused-member-function" +#endif + struct JsonDocument : public rapidjson::Document { JsonDocument() { assert(s_pActiveDocument == @@ -1466,7 +1609,13 @@ struct JsonDocument : public rapidjson::Document { private: bool isNil = false; }; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + #endif // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR + #else using nlohmann::json; using json_const_iterator = json::const_iterator; @@ -1477,6 +1626,7 @@ using JsonDocument = json; void JsonParse(JsonDocument &doc, const char *str, size_t length, bool throwExc = false) { #ifdef TINYGLTF_USE_RAPIDJSON + (void)throwExc; doc.Parse(str, length); #else doc = json::parse(str, str + length, nullptr, throwExc); @@ -1552,7 +1702,8 @@ bool Accessor::operator==(const Accessor &other) const { return this->bufferView == other.bufferView && this->byteOffset == other.byteOffset && this->componentType == other.componentType && - this->count == other.count && this->extras == other.extras && + this->count == other.count && this->extensions == other.extensions && + this->extras == other.extras && Equals(this->maxValues, other.maxValues) && Equals(this->minValues, other.minValues) && this->name == other.name && this->normalized == other.normalized && this->type == other.type; @@ -1569,7 +1720,8 @@ bool AnimationChannel::operator==(const AnimationChannel &other) const { this->sampler == other.sampler; } bool AnimationSampler::operator==(const AnimationSampler &other) const { - return this->extras == other.extras && this->input == other.input && + return this->extras == other.extras && this->extensions == other.extensions && + this->input == other.input && this->interpolation == other.interpolation && this->output == other.output; } @@ -1580,14 +1732,16 @@ bool Asset::operator==(const Asset &other) const { this->minVersion == other.minVersion && this->version == other.version; } bool Buffer::operator==(const Buffer &other) const { - return this->data == other.data && this->extras == other.extras && - this->name == other.name && this->uri == other.uri; + return this->data == other.data && this->extensions == other.extensions && + this->extras == other.extras && this->name == other.name && + this->uri == other.uri; } bool BufferView::operator==(const BufferView &other) const { return this->buffer == other.buffer && this->byteLength == other.byteLength && this->byteOffset == other.byteOffset && this->byteStride == other.byteStride && this->name == other.name && - this->target == other.target && this->extras == other.extras && + this->target == other.target && this->extensions == other.extensions && + this->extras == other.extras && this->dracoDecoded == other.dracoDecoded; } bool Camera::operator==(const Camera &other) const { @@ -1598,7 +1752,8 @@ bool Camera::operator==(const Camera &other) const { } bool Image::operator==(const Image &other) const { return this->bufferView == other.bufferView && - this->component == other.component && this->extras == other.extras && + this->component == other.component && + this->extensions == other.extensions && this->extras == other.extras && this->height == other.height && this->image == other.image && this->mimeType == other.mimeType && this->name == other.name && this->uri == other.uri && this->width == other.width; @@ -1699,7 +1854,8 @@ bool Primitive::operator==(const Primitive &other) const { this->mode == other.mode && this->targets == other.targets; } bool Sampler::operator==(const Sampler &other) const { - return this->extras == other.extras && this->magFilter == other.magFilter && + return this->extensions == other.extensions && this->extras == other.extras && + this->magFilter == other.magFilter && this->minFilter == other.minFilter && this->name == other.name && this->wrapR == other.wrapR && this->wrapS == other.wrapS && this->wrapT == other.wrapT; @@ -1709,7 +1865,8 @@ bool Scene::operator==(const Scene &other) const { this->name == other.name && this->nodes == other.nodes; } bool Skin::operator==(const Skin &other) const { - return this->inverseBindMatrices == other.inverseBindMatrices && + return this->extensions == other.extensions && this->extras == other.extras && + this->inverseBindMatrices == other.inverseBindMatrices && this->joints == other.joints && this->name == other.name && this->skeleton == other.skeleton; } @@ -2690,6 +2847,25 @@ const json &GetValue(json_const_iterator &it) { return it.value(); #endif } + +std::string JsonToString(const json &o, int spacing = -1) { +#ifdef TINYGLTF_USE_RAPIDJSON + using namespace rapidjson; + StringBuffer buffer; + if (spacing == -1) { + Writer writer(buffer); + o.Accept(writer); + } else { + PrettyWriter writer(buffer); + writer.SetIndent(' ', uint32_t(spacing)); + o.Accept(writer); + } + return buffer.GetString(); +#else + return o.dump(spacing); +#endif +} + } // namespace static bool ParseJsonAsValue(Value *ret, const json &o) { @@ -2737,9 +2913,8 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { } break; case Type::kNullType: - default: - // default: break; + // all types are covered, so no `case default` } #else switch (o.type()) { @@ -3275,7 +3450,8 @@ static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err, return true; } -static bool ParseAsset(Asset *asset, std::string *err, const json &o) { +static bool ParseAsset(Asset *asset, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&asset->version, err, o, "version", true, "Asset"); ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset"); ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset"); @@ -3285,11 +3461,27 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) { // Unity exporter version is added as extra here ParseExtrasProperty(&(asset->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + asset->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + asset->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } 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, LoadImageDataFunction *LoadImageData = nullptr, void *load_image_user_data = nullptr) { @@ -3326,6 +3518,21 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, ParseExtensionsProperty(&image->extensions, err, o); ParseExtrasProperty(&image->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator eit; + if (FindMember(o, "extensions", eit)) { + image->extensions_json_string = JsonToString(GetValue(eit)); + } + } + { + json_const_iterator eit; + if (FindMember(o, "extras", eit)) { + image->extras_json_string = JsonToString(GetValue(eit)); + } + } + } + if (hasBufferView) { int bufferView = -1; if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) { @@ -3417,6 +3624,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, } static bool ParseTexture(Texture *texture, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions, const std::string &basedir) { (void)basedir; int sampler = -1; @@ -3431,13 +3639,29 @@ static bool ParseTexture(Texture *texture, std::string *err, const json &o, ParseExtensionsProperty(&texture->extensions, err, o); ParseExtrasProperty(&texture->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + texture->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + texture->extras_json_string = JsonToString(GetValue(it)); + } + } + } + ParseStringProperty(&texture->name, err, o, "name", false); return true; } -static bool ParseTextureInfo(TextureInfo *texinfo, std::string *err, - const json &o) { +static bool ParseTextureInfo( + TextureInfo *texinfo, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; } @@ -3452,11 +3676,27 @@ static bool ParseTextureInfo(TextureInfo *texinfo, std::string *err, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + texinfo->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseNormalTextureInfo(NormalTextureInfo *texinfo, std::string *err, - const json &o) { +static bool ParseNormalTextureInfo( + NormalTextureInfo *texinfo, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; } @@ -3472,11 +3712,27 @@ static bool ParseNormalTextureInfo(NormalTextureInfo *texinfo, std::string *err, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + texinfo->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseOcclusionTextureInfo(OcclusionTextureInfo *texinfo, - std::string *err, const json &o) { +static bool ParseOcclusionTextureInfo( + OcclusionTextureInfo *texinfo, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; } @@ -3492,10 +3748,26 @@ static bool ParseOcclusionTextureInfo(OcclusionTextureInfo *texinfo, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + texinfo->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } 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, const unsigned char *bin_data = nullptr, @@ -3596,11 +3868,30 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, ParseStringProperty(&buffer->name, err, o, "name", false); + ParseExtensionsProperty(&buffer->extensions, err, o); + ParseExtrasProperty(&buffer->extras, o); + + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + buffer->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + buffer->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseBufferView(BufferView *bufferView, std::string *err, - const json &o) { +static bool ParseBufferView( + BufferView *bufferView, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { int buffer = -1; if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) { return false; @@ -3649,6 +3940,24 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, ParseStringProperty(&bufferView->name, err, o, "name", false); + ParseExtensionsProperty(&bufferView->extensions, err, o); + ParseExtrasProperty(&bufferView->extras, o); + + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + bufferView->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + bufferView->extras_json_string = JsonToString(GetValue(it)); + } + } + } + bufferView->buffer = buffer; bufferView->byteOffset = byteOffset; bufferView->byteLength = byteLength; @@ -3704,7 +4013,8 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err, return true; } -static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { +static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { int bufferView = -1; ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor"); @@ -3783,8 +4093,24 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { } } + ParseExtensionsProperty(&(accessor->extensions), err, o); ParseExtrasProperty(&(accessor->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + accessor->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + accessor->extras_json_string = JsonToString(GetValue(it)); + } + } + } + // check if accessor has a "sparse" object: json_const_iterator iterator; if (FindMember(o, "sparse", iterator)) { @@ -3988,7 +4314,8 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, #endif static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, - const json &o) { + const json &o, + bool store_original_json_for_extras_and_extensions) { int material = -1; ParseIntegerProperty(&material, err, o, "material", false); primitive->material = material; @@ -4030,9 +4357,23 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, } ParseExtrasProperty(&(primitive->extras), o); - ParseExtensionsProperty(&primitive->extensions, err, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + primitive->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + primitive->extras_json_string = JsonToString(GetValue(it)); + } + } + } + #ifdef TINYGLTF_ENABLE_DRACO auto dracoExtension = primitive->extensions.find("KHR_draco_mesh_compression"); @@ -4046,8 +4387,8 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, return true; } -static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, - const json &o) { +static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&mesh->name, err, o, "name", false); mesh->primitives.clear(); @@ -4058,7 +4399,8 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, for (json_const_array_iterator i = ArrayBegin(GetValue(primObject)); i != primEnd; ++i) { Primitive primitive; - if (ParsePrimitive(&primitive, model, err, *i)) { + if (ParsePrimitive(&primitive, model, err, *i, + store_original_json_for_extras_and_extensions)) { // Only add the primitive if the parsing succeeds. mesh->primitives.emplace_back(std::move(primitive)); } @@ -4071,10 +4413,26 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, ParseExtensionsProperty(&mesh->extensions, err, o); ParseExtrasProperty(&(mesh->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + mesh->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + mesh->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseNode(Node *node, std::string *err, const json &o) { +static bool ParseNode(Node *node, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&node->name, err, o, "name", false); int skin = -1; @@ -4104,11 +4462,27 @@ static bool ParseNode(Node *node, std::string *err, const json &o) { ParseExtensionsProperty(&node->extensions, err, o); ParseExtrasProperty(&(node->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + node->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + node->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParsePbrMetallicRoughness(PbrMetallicRoughness *pbr, - std::string *err, const json &o) { +static bool ParsePbrMetallicRoughness( + PbrMetallicRoughness *pbr, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (pbr == nullptr) { return false; } @@ -4131,14 +4505,16 @@ static bool ParsePbrMetallicRoughness(PbrMetallicRoughness *pbr, { json_const_iterator it; if (FindMember(o, "baseColorTexture", it)) { - ParseTextureInfo(&pbr->baseColorTexture, err, GetValue(it)); + ParseTextureInfo(&pbr->baseColorTexture, err, GetValue(it), + store_original_json_for_extras_and_extensions); } } { json_const_iterator it; if (FindMember(o, "metallicRoughnessTexture", it)) { - ParseTextureInfo(&pbr->metallicRoughnessTexture, err, GetValue(it)); + ParseTextureInfo(&pbr->metallicRoughnessTexture, err, GetValue(it), + store_original_json_for_extras_and_extensions); } } @@ -4148,10 +4524,26 @@ static bool ParsePbrMetallicRoughness(PbrMetallicRoughness *pbr, ParseExtensionsProperty(&pbr->extensions, err, o); ParseExtrasProperty(&pbr->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + pbr->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + pbr->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseMaterial(Material *material, std::string *err, const json &o) { +static bool ParseMaterial(Material *material, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&material->name, err, o, "name", /* required */ false); if (ParseNumberArrayProperty(&material->emissiveFactor, err, o, @@ -4182,28 +4574,32 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) { json_const_iterator it; if (FindMember(o, "pbrMetallicRoughness", it)) { ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err, - GetValue(it)); + GetValue(it), + store_original_json_for_extras_and_extensions); } } { json_const_iterator it; if (FindMember(o, "normalTexture", it)) { - ParseNormalTextureInfo(&material->normalTexture, err, GetValue(it)); + ParseNormalTextureInfo(&material->normalTexture, err, GetValue(it), + store_original_json_for_extras_and_extensions); } } { json_const_iterator it; if (FindMember(o, "occlusionTexture", it)) { - ParseOcclusionTextureInfo(&material->occlusionTexture, err, GetValue(it)); + ParseOcclusionTextureInfo(&material->occlusionTexture, err, GetValue(it), + store_original_json_for_extras_and_extensions); } } { json_const_iterator it; if (FindMember(o, "emissiveTexture", it)) { - ParseTextureInfo(&material->emissiveTexture, err, GetValue(it)); + ParseTextureInfo(&material->emissiveTexture, err, GetValue(it), + store_original_json_for_extras_and_extensions); } } @@ -4253,11 +4649,27 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) { ParseExtensionsProperty(&material->extensions, err, o); ParseExtrasProperty(&(material->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator eit; + if (FindMember(o, "extensions", eit)) { + material->extensions_json_string = JsonToString(GetValue(eit)); + } + } + { + json_const_iterator eit; + if (FindMember(o, "extras", eit)) { + material->extras_json_string = JsonToString(GetValue(eit)); + } + } + } + return true; } -static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, - const json &o) { +static bool ParseAnimationChannel( + AnimationChannel *channel, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { int samplerIndex = -1; int targetIndex = -1; if (!ParseIntegerProperty(&samplerIndex, err, o, "sampler", true, @@ -4294,11 +4706,27 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, ParseExtensionsProperty(&channel->extensions, err, o); ParseExtrasProperty(&(channel->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + channel->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + channel->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } static bool ParseAnimation(Animation *animation, std::string *err, - const json &o) { + const json &o, + bool store_original_json_for_extras_and_extensions) { { json_const_iterator channelsIt; if (FindMember(o, "channels", channelsIt) && @@ -4307,7 +4735,9 @@ static bool ParseAnimation(Animation *animation, std::string *err, for (json_const_array_iterator i = ArrayBegin(GetValue(channelsIt)); i != channelEnd; ++i) { AnimationChannel channel; - if (ParseAnimationChannel(&channel, err, *i)) { + if (ParseAnimationChannel( + &channel, err, *i, + store_original_json_for_extras_and_extensions)) { // Only add the channel if the parsing succeeds. animation->channels.emplace_back(std::move(channel)); } @@ -4345,7 +4775,24 @@ static bool ParseAnimation(Animation *animation, std::string *err, } sampler.input = inputIndex; sampler.output = outputIndex; + ParseExtensionsProperty(&(sampler.extensions), err, o); ParseExtrasProperty(&(sampler.extras), s); + + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator eit; + if (FindMember(o, "extensions", eit)) { + sampler.extensions_json_string = JsonToString(GetValue(eit)); + } + } + { + json_const_iterator eit; + if (FindMember(o, "extras", eit)) { + sampler.extras_json_string = JsonToString(GetValue(eit)); + } + } + } + animation->samplers.emplace_back(std::move(sampler)); } } @@ -4356,10 +4803,26 @@ static bool ParseAnimation(Animation *animation, std::string *err, ParseExtensionsProperty(&animation->extensions, err, o); ParseExtrasProperty(&(animation->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + animation->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + animation->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) { +static bool ParseSampler(Sampler *sampler, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&sampler->name, err, o, "name", false); int minFilter = -1; @@ -4382,12 +4845,29 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) { sampler->wrapT = wrapT; sampler->wrapR = wrapR; + ParseExtensionsProperty(&(sampler->extensions), err, o); ParseExtrasProperty(&(sampler->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + sampler->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + sampler->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseSkin(Skin *skin, std::string *err, const json &o) { +static bool ParseSkin(Skin *skin, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&skin->name, err, o, "name", false, "Skin"); std::vector joints; @@ -4404,11 +4884,30 @@ static bool ParseSkin(Skin *skin, std::string *err, const json &o) { ParseIntegerProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin"); skin->inverseBindMatrices = invBind; + ParseExtensionsProperty(&(skin->extensions), err, o); + ParseExtrasProperty(&(skin->extras), o); + + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + skin->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + skin->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParsePerspectiveCamera(PerspectiveCamera *camera, std::string *err, - const json &o) { +static bool ParsePerspectiveCamera( + PerspectiveCamera *camera, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { double yfov = 0.0; if (!ParseNumberProperty(&yfov, err, o, "yfov", true, "OrthographicCamera")) { return false; @@ -4435,25 +4934,57 @@ static bool ParsePerspectiveCamera(PerspectiveCamera *camera, std::string *err, ParseExtensionsProperty(&camera->extensions, err, o); ParseExtrasProperty(&(camera->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + camera->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + camera->extras_json_string = JsonToString(GetValue(it)); + } + } + } + // TODO(syoyo): Validate parameter values. return true; } -static bool ParseSpotLight(SpotLight *light, std::string *err, const json &o) { +static bool ParseSpotLight(SpotLight *light, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { ParseNumberProperty(&light->innerConeAngle, err, o, "innerConeAngle", false); ParseNumberProperty(&light->outerConeAngle, err, o, "outerConeAngle", false); ParseExtensionsProperty(&light->extensions, err, o); ParseExtrasProperty(&light->extras, o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + light->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + light->extras_json_string = JsonToString(GetValue(it)); + } + } + } + // TODO(syoyo): Validate parameter values. return true; } -static bool ParseOrthographicCamera(OrthographicCamera *camera, - std::string *err, const json &o) { +static bool ParseOrthographicCamera( + OrthographicCamera *camera, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { double xmag = 0.0; if (!ParseNumberProperty(&xmag, err, o, "xmag", true, "OrthographicCamera")) { return false; @@ -4478,6 +5009,21 @@ static bool ParseOrthographicCamera(OrthographicCamera *camera, ParseExtensionsProperty(&camera->extensions, err, o); ParseExtrasProperty(&(camera->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + camera->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + camera->extras_json_string = JsonToString(GetValue(it)); + } + } + } + camera->xmag = xmag; camera->ymag = ymag; camera->zfar = zfar; @@ -4488,7 +5034,8 @@ static bool ParseOrthographicCamera(OrthographicCamera *camera, return true; } -static bool ParseCamera(Camera *camera, std::string *err, const json &o) { +static bool ParseCamera(Camera *camera, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (!ParseStringProperty(&camera->type, err, o, "type", true, "Camera")) { return false; } @@ -4514,7 +5061,9 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o) { return false; } - if (!ParseOrthographicCamera(&camera->orthographic, err, v)) { + if (!ParseOrthographicCamera( + &camera->orthographic, err, v, + store_original_json_for_extras_and_extensions)) { return false; } } else if (camera->type.compare("perspective") == 0) { @@ -4538,7 +5087,9 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o) { return false; } - if (!ParsePerspectiveCamera(&camera->perspective, err, v)) { + if (!ParsePerspectiveCamera( + &camera->perspective, err, v, + store_original_json_for_extras_and_extensions)) { return false; } } else { @@ -4556,10 +5107,26 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o) { ParseExtensionsProperty(&camera->extensions, err, o); ParseExtrasProperty(&(camera->extras), o); + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + camera->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + camera->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } -static bool ParseLight(Light *light, std::string *err, const json &o) { +static bool ParseLight(Light *light, std::string *err, const json &o, + bool store_original_json_for_extras_and_extensions) { if (!ParseStringProperty(&light->type, err, o, "type", true)) { return false; } @@ -4585,7 +5152,8 @@ static bool ParseLight(Light *light, std::string *err, const json &o) { return false; } - if (!ParseSpotLight(&light->spot, err, v)) { + if (!ParseSpotLight(&light->spot, err, v, + store_original_json_for_extras_and_extensions)) { return false; } } @@ -4596,6 +5164,22 @@ static bool ParseLight(Light *light, std::string *err, const json &o) { ParseNumberProperty(&light->intensity, err, o, "intensity", false); ParseExtensionsProperty(&light->extensions, err, o); ParseExtrasProperty(&(light->extras), o); + + if (store_original_json_for_extras_and_extensions) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + light->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + light->extras_json_string = JsonToString(GetValue(it)); + } + } + } + return true; } @@ -4743,7 +5327,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, if (FindMember(v, "asset", it) && IsObject(GetValue(it))) { const json &root = GetValue(it); - ParseAsset(&model->asset, err, root); + ParseAsset(&model->asset, err, root, + store_original_json_for_extras_and_extensions_); } } @@ -4799,8 +5384,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Buffer buffer; - if (!ParseBuffer(&buffer, err, o, &fs, base_dir, is_binary_, bin_data_, - bin_size_)) { + if (!ParseBuffer(&buffer, err, o, + store_original_json_for_extras_and_extensions_, &fs, + base_dir, is_binary_, bin_data_, bin_size_)) { return false; } @@ -4822,7 +5408,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } BufferView bufferView; - if (!ParseBufferView(&bufferView, err, o)) { + if (!ParseBufferView(&bufferView, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -4845,7 +5432,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Accessor accessor; - if (!ParseAccessor(&accessor, err, o)) { + if (!ParseAccessor(&accessor, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -4868,7 +5456,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Mesh mesh; - if (!ParseMesh(&mesh, model, err, o)) { + if (!ParseMesh(&mesh, model, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -4932,7 +5521,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Node node; - if (!ParseNode(&node, err, o)) { + if (!ParseNode(&node, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -4965,6 +5555,21 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, ParseExtensionsProperty(&scene.extensions, err, o); ParseExtrasProperty(&scene.extras, o); + if (store_original_json_for_extras_and_extensions_) { + { + json_const_iterator it; + if (FindMember(o, "extensions", it)) { + model->extensions_json_string = JsonToString(GetValue(it)); + } + } + { + json_const_iterator it; + if (FindMember(o, "extras", it)) { + model->extras_json_string = JsonToString(GetValue(it)); + } + } + } + model->scenes.emplace_back(std::move(scene)); return true; }); @@ -4995,7 +5600,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, Material material; ParseStringProperty(&material.name, err, o, "name", false); - if (!ParseMaterial(&material, err, o)) { + if (!ParseMaterial(&material, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -5019,8 +5625,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Image image; - if (!ParseImage(&image, idx, err, warn, o, base_dir, &fs, - &this->LoadImageData, load_image_user_data_)) { + if (!ParseImage(&image, idx, err, warn, o, + store_original_json_for_extras_and_extensions_, base_dir, + &fs, &this->LoadImageData, load_image_user_data_)) { return false; } @@ -5084,7 +5691,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Texture texture; - if (!ParseTexture(&texture, err, o, base_dir)) { + if (!ParseTexture(&texture, err, o, + store_original_json_for_extras_and_extensions_, + base_dir)) { return false; } @@ -5107,7 +5716,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Animation animation; - if (!ParseAnimation(&animation, err, o)) { + if (!ParseAnimation(&animation, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -5130,7 +5740,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Skin skin; - if (!ParseSkin(&skin, err, o)) { + if (!ParseSkin(&skin, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -5153,7 +5764,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Sampler sampler; - if (!ParseSampler(&sampler, err, o)) { + if (!ParseSampler(&sampler, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -5176,7 +5788,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } Camera camera; - if (!ParseCamera(&camera, err, o)) { + if (!ParseCamera(&camera, err, o, + store_original_json_for_extras_and_extensions_)) { return false; } @@ -5216,7 +5829,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, auto arrayItEnd(ArrayEnd(lights)); for (; arrayIt != arrayItEnd; ++arrayIt) { Light light; - if (!ParseLight(&light, err, *arrayIt)) { + if (!ParseLight(&light, err, *arrayIt, + store_original_json_for_extras_and_extensions_)) { return false; } model->lights.emplace_back(std::move(light)); @@ -5230,6 +5844,11 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 19. Parse Extras ParseExtrasProperty(&model->extras, v); + if (store_original_json_for_extras_and_extensions_) { + model->extras_json_string = JsonToString(v["extras"]); + model->extensions_json_string = JsonToString(v["extensions"]); + } + return true; } @@ -5407,24 +6026,6 @@ json JsonFromString(const char *s) { #endif } -std::string JsonToString(const json &o, int spacing = -1) { -#ifdef TINYGLTF_USE_RAPIDJSON - using namespace rapidjson; - StringBuffer buffer; - if (spacing == -1) { - Writer writer(buffer); - o.Accept(writer); - } else { - PrettyWriter writer(buffer); - writer.SetIndent(' ', spacing); - o.Accept(writer); - } - return buffer.GetString(); -#else - return o.dump(spacing); -#endif -} - void JsonAssign(json &dest, const json &src) { #ifdef TINYGLTF_USE_RAPIDJSON dest.CopyFrom(src, GetAllocator()); @@ -6130,7 +6731,7 @@ static void SerializeSpotLight(SpotLight &spot, json &o) { SerializeNumberProperty("outerConeAngle", spot.outerConeAngle, o); SerializeExtensionMap(spot.extensions, o); if (spot.extras.Type() != NULL_TYPE) { - SerializeValue("extras", spot.extras, o); + SerializeValue("extras", spot.extras, o); } } @@ -6147,7 +6748,7 @@ static void SerializeGltfLight(Light &light, json &o) { } SerializeExtensionMap(light.extensions, o); if (light.extras.Type() != NULL_TYPE) { - SerializeValue("extras", light.extras, o); + SerializeValue("extras", light.extras, o); } }