From d4ea67cae194b569ea58e73ee1553fb1be1de077 Mon Sep 17 00:00:00 2001 From: Thomas Gamper Date: Thu, 23 Nov 2023 11:59:18 +0100 Subject: [PATCH] fix #457 tiny_gltf.h - make sure to serialize null node as empty object; tester.cc - add respective test case --- tests/tester.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ tiny_gltf.h | 10 ++++++++++ 2 files changed, 59 insertions(+) diff --git a/tests/tester.cc b/tests/tester.cc index daf088f..1117a80 100644 --- a/tests/tester.cc +++ b/tests/tester.cc @@ -779,3 +779,52 @@ TEST_CASE("default-material", "[issue-459]") { CHECK(mat.occlusionTexture.index == -1); CHECK(mat.emissiveTexture.index == -1); } + +TEST_CASE("serialize-empty-node", "[issue-457]") { + tinygltf::Model m; + // Add default constructed node to model + m.nodes.push_back({}); + // Add scene to model + m.scenes.push_back({}); + // The scene's only node is the empty node + m.scenes.front().nodes.push_back(0); + + // Serialize model to output stream + std::stringstream os; + tinygltf::TinyGLTF ctx; + bool ret = ctx.WriteGltfSceneToStream(&m, os, false, false); + REQUIRE(true == ret); + + // Parse serialized model + nlohmann::json j = nlohmann::json::parse(os.str()); + + // Serialized nodes shall hold an empty object that + // represents the default constructed node + REQUIRE(j.find("nodes") != j.end()); + REQUIRE(j["nodes"].is_array()); + REQUIRE(1 == j["nodes"].size()); + CHECK(j["nodes"][0].is_object()); + CHECK(j["nodes"][0].empty()); + + // We also want to make sure that the serialized scene + // is referencing the empty node. + + // There shall be a single serialized scene + auto scenes = j.find("scenes"); + REQUIRE(scenes != j.end()); + REQUIRE(scenes->is_array()); + REQUIRE(1 == scenes->size()); + auto scene = scenes->at(0); + REQUIRE(scene.is_object()); + // The scene's nodes array shall hold a reference + // to the single node + auto nodes = scene.find("nodes"); + REQUIRE(nodes != scene.end()); + REQUIRE(nodes->is_array()); + REQUIRE(1 == nodes->size()); + auto node = nodes->at(0); + CHECK(node.is_number_integer()); + int idx = -1; + node.get_to(idx); + CHECK(0 == idx); +} diff --git a/tiny_gltf.h b/tiny_gltf.h index 7991303..7275d8d 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -8036,6 +8036,16 @@ static void SerializeGltfModel(const Model *model, detail::json &o) { for (unsigned int i = 0; i < model->nodes.size(); ++i) { detail::json node; SerializeGltfNode(model->nodes[i], node); + + if (detail::JsonIsNull(node)) { + // Issue 457. + // `node` does not have any required parameters, + // so the result may be null(unmodified) when all node parameters + // have default value. + // + // null is not allowed thus we create an empty JSON object. + detail::JsonSetObject(node); + } detail::JsonPushBack(nodes, std::move(node)); } detail::JsonAddMember(o, "nodes", std::move(nodes));