void Importer::mergeMapFields(Node& target, const Node& import) { for (const auto& entry : import) { const auto &key = entry.first.Scalar(); // do not merge ignore property if (key == "import") { continue; } if (!target[key]) { target[key] = entry.second; continue; } switch(entry.second.Type()) { case NodeType::Scalar: case NodeType::Sequence: target[key] = entry.second; break; case NodeType::Map: { Node newTarget = target[key]; mergeMapFields(newTarget, entry.second); break; } default: break; } } }
void Importer::mergeMapFields(Node& target, const Node& import) { for (const auto& entry : import) { const auto& key = entry.first.Scalar(); const auto& source = entry.second; auto dest = target[key]; if (!dest) { dest = source; continue; } if (dest.Type() != source.Type()) { LOGN("Merging different node types: '%s'\n'%s'\n<==\n'%s'", key.c_str(), Dump(dest).c_str(), Dump(source).c_str()); } switch(dest.Type()) { case NodeType::Null: case NodeType::Scalar: case NodeType::Sequence: dest = source; break; case NodeType::Map: { auto newTarget = dest; if (source.IsMap()) { mergeMapFields(newTarget, source); } else { dest = source; } break; } default: // NodeType::Undefined is handled above by checking (!dest). // All types are handled, so this should never be reached. assert(false); break; } } }
Node Importer::importScenes(const std::string& scenePath) { auto importScenesSorted = getImportOrder(scenePath); if (importScenesSorted.size() == 1) { return m_scenes[importScenesSorted[0]]; } Node root = Node(); for (auto& import : importScenesSorted) { const auto& importRoot = m_scenes[import]; if (!importRoot.IsMap()) { continue; } mergeMapFields(root, importRoot); } return root; }
void Importer::importScenesRecursive(Node& root, const Url& sceneUrl, std::vector<Url>& sceneStack) { LOGD("Starting importing Scene: %s", sceneUrl.string().c_str()); for (const auto& s : sceneStack) { if (sceneUrl == s) { LOGE("%s will cause a cyclic import. Stopping this scene from being imported", sceneUrl.string().c_str()); return; } } sceneStack.push_back(sceneUrl); auto sceneNode = m_importedScenes[sceneUrl]; if (!sceneNode.IsDefined() || !sceneNode.IsMap()) { return; } auto imports = getResolvedImportUrls(sceneNode, sceneUrl); // Don't want to merge imports, so remove them here. sceneNode.remove("import"); for (const auto& url : imports) { importScenesRecursive(root, url, sceneStack); } sceneStack.pop_back(); mergeMapFields(root, sceneNode); resolveSceneUrls(root, sceneUrl); }