diff --git a/data/web/scenelicense/main.hbs b/data/web/scenelicense/main.hbs new file mode 100644 index 0000000000..786b51a823 --- /dev/null +++ b/data/web/scenelicense/main.hbs @@ -0,0 +1,9 @@ +
+
+

OpenSpace Scene License Information

+

Version: {{version.[0]}}.{{version.[1]}}.{{version.[2]}}

+ {{#each sceneLicenses}} + {{> scenelicense}} + {{/each}} +
+
\ No newline at end of file diff --git a/data/web/scenelicense/scenelicense.hbs b/data/web/scenelicense/scenelicense.hbs new file mode 100644 index 0000000000..2bd8e98d20 --- /dev/null +++ b/data/web/scenelicense/scenelicense.hbs @@ -0,0 +1,16 @@ +
+
+
+

+ + {{module}} + +

{{name}}

+
+

{{attribution}}

+

{{url}}

+

{{licenseText}}

+

+
+
+
diff --git a/data/web/scenelicense/script.js b/data/web/scenelicense/script.js new file mode 100644 index 0000000000..e0594d2829 --- /dev/null +++ b/data/web/scenelicense/script.js @@ -0,0 +1,28 @@ +window.onload = function () { + var mainTemplateElement = document.getElementById('mainTemplate'); + var mainTemplate = Handlebars.compile(mainTemplateElement.innerHTML); + + var sceneLicenseTemplate = document.getElementById('sceneLicenseTemplate'); + Handlebars.registerPartial('scenelicense', sceneLicenseTemplate.innerHTML); + + Handlebars.registerHelper('urlify', function(options, context) { + var data = context.data; + var identifier = options.replace(" ", "-").toLowerCase(); + + while (data = data._parent) { + if (data.key !== undefined) { + identifier = data.key + "-" + identifier; + } + } + + return identifier; + }); + + var data = { + sceneLicenses: sceneLicenses, + version: version + } + + var contents = mainTemplate(data); + document.body.innerHTML = contents; +} \ No newline at end of file diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 75163f2c75..69a83bb6a8 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -67,6 +67,8 @@ public: static const std::string KeyDocumentation; /// The key that stores the factory documentation values static const std::string KeyFactoryDocumentation; + /// The key that stores the scene license documentation values + static const std::string KeySceneLicenseDocumentation; /// The key that stores the location of the scene file that is initially loaded static const std::string KeyConfigScene; /// The key that stores the location of the tasks files diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index ff24b3633f..0ccd476883 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -32,9 +32,12 @@ #include #include +#include +#include +#include #include #include -#include + #include namespace ghoul { class Dictionary; } @@ -122,6 +125,8 @@ public: */ void removeNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes); + void addSceneLicense(SceneLicense license); + /** * Update dependencies. */ @@ -132,6 +137,14 @@ public: */ const std::vector& allSceneGraphNodes() const; + /** + * Write information about the license information for the scenegraph nodes that are + * contained in this scene + * \param path The file path that will contain the documentation about the licenses + * used in this scene + */ + void writeSceneLicenseDocumentation(const std::string& path) const; + /** * Return a a map from name to scene graph node. */ @@ -160,6 +173,8 @@ private: std::vector _circularNodes; std::map _nodesByName; + std::vector _licenses; + std::mutex _programUpdateLock; std::set _programsToUpdate; std::vector> _programs; diff --git a/include/openspace/scene/scenelicense.h b/include/openspace/scene/scenelicense.h new file mode 100644 index 0000000000..fab818aad4 --- /dev/null +++ b/include/openspace/scene/scenelicense.h @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___SCENELICENSE___H__ +#define __OPENSPACE_CORE___SCENELICENSE___H__ + +#include + +#include +#include + +namespace ghoul { + class Dictionary; +} // namespace ghoul + +namespace openspace { + +struct SceneLicense { + // module must not be empty + SceneLicense(const ghoul::Dictionary& dictionary, std::string module); + + std::string module; + + std::string name; + std::string attribution; + std::string url; + std::string licenseText; + + static documentation::Documentation Documentation(); +}; + +void writeSceneLicenseDocumentation(const std::vector& licenses, + const std::string& file, const std::string& type); + +} // namespace openspace + +#endif // __OPENSPACE_CORE___SCENELICENSE___H__ diff --git a/include/openspace/scene/scenelicensewriter.h b/include/openspace/scene/scenelicensewriter.h new file mode 100644 index 0000000000..0bd591d139 --- /dev/null +++ b/include/openspace/scene/scenelicensewriter.h @@ -0,0 +1,48 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___SCENELICENSEWRITER___H__ +#define __OPENSPACE_CORE___SCENELICENSEWRITER___H__ + +#include + +#include + +#include + +namespace openspace { + +class SceneLicenseWriter : public DocumentationGenerator { +public: + SceneLicenseWriter(const std::vector& licenses); + +private: + std::string generateJson() const override; + + const std::vector& _licenses; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___SCENELICENSEWRITER___H__ diff --git a/include/openspace/scene/sceneloader.h b/include/openspace/scene/sceneloader.h index ee828985a4..140bbc0f29 100644 --- a/include/openspace/scene/sceneloader.h +++ b/include/openspace/scene/sceneloader.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___SCENELOADER___H__ #include +#include #include #include @@ -33,6 +34,7 @@ #include #include +#include namespace openspace { @@ -51,7 +53,8 @@ public: /** * Import a directory of scene contents into an existing scene. */ - std::vector importDirectory(Scene& scene, const std::string& directory); + std::pair, std::vector> + importDirectory(Scene& scene, const std::string& directory); /** * Import a scene graph node from a dictionary into an existing scene. @@ -98,10 +101,16 @@ private: */ std::vector loadModule(const std::string& path, lua_State* luaState); + /** + * Loads an existing license file + */ + std::vector loadLicense(const std::string& path, std::string module); + /** * Load a directory. */ - std::vector loadDirectory(const std::string& path, lua_State* luaState); + std::pair, std::vector> + loadDirectory(const std::string& path, lua_State* luaState); /** * Load a camera from a dictionary diff --git a/openspace.cfg b/openspace.cfg index d92d8a3d27..557e5b1ba0 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -76,6 +76,7 @@ return { KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", Documentation = "${DOCUMENTATION}/Documentation.html", FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", + LicenseDocumentation = "${DOCUMENTATION}/License.html", -- CheckOpenGLState = true, -- LogEachOpenGLCall = true, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04cb2e242e..9325bfa8e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -132,6 +132,8 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/scene.cpp ${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl ${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl + ${OPENSPACE_BASE_DIR}/src/scene/scenelicense.cpp + ${OPENSPACE_BASE_DIR}/src/scene/scenelicensewriter.cpp ${OPENSPACE_BASE_DIR}/src/scene/sceneloader.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenemanager.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp @@ -286,6 +288,8 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h + ${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicense.h + ${OPENSPACE_BASE_DIR}/include/openspace/scene/scenelicensewriter.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/sceneloader.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scenemanager.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scenegraphnode.h diff --git a/src/documentation/documentationgenerator.cpp b/src/documentation/documentationgenerator.cpp index 75026e4f30..f594855e02 100644 --- a/src/documentation/documentationgenerator.cpp +++ b/src/documentation/documentationgenerator.cpp @@ -30,6 +30,8 @@ #include #include +#include + #include namespace { @@ -158,6 +160,12 @@ std::string escapedJson(const std::string& text) { case '\\': jsonString += "\\\\"; break; + case '\n': + jsonString += "\\\\n"; + break; + case '\r': + jsonString += "\\r"; + break; default: jsonString += c; } diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index 29ac9b7ea2..b8ce887c0a 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -58,6 +58,7 @@ const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumenta const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts"; const string ConfigurationManager::KeyDocumentation = "Documentation"; const string ConfigurationManager::KeyFactoryDocumentation = "FactoryDocumentation"; +const string ConfigurationManager::KeySceneLicenseDocumentation = "LicenseDocumentation"; const string ConfigurationManager::KeyConfigScene = "Scene"; const string ConfigurationManager::KeyConfigTasksRoot = "TasksRoot"; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 5731777510..5d13ee7742 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -200,6 +200,14 @@ documentation::Documentation ConfigurationManager::Documentation() { "created in the current application configuration. Any previous file in this " "location will be silently overritten." }, + { + ConfigurationManager::KeySceneLicenseDocumentation, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing the scene license " + "information. Any previous file in this location will be silently " + "overwritten." + }, { ConfigurationManager::KeyLauncher, new TableVerifier({ diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 9b98cb2fc4..ce3cf6629c 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -645,6 +646,15 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { ); } + if (configurationManager().hasKey(ConfigurationManager::KeySceneLicenseDocumentation)) + { + scene->writeSceneLicenseDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeySceneLicenseDocumentation + )) + ); + } + // If a PropertyDocumentationFile was specified, generate it now. if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) { scene->writeDocumentation( diff --git a/src/interaction/keybindingmanager.cpp b/src/interaction/keybindingmanager.cpp index 6cee3a8788..b702751136 100644 --- a/src/interaction/keybindingmanager.cpp +++ b/src/interaction/keybindingmanager.cpp @@ -138,7 +138,7 @@ std::string KeyBindingManager::generateJson() const { } return jsonString; -} +} scripting::LuaLibrary KeyBindingManager::luaLibrary() { return { diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index b9c77b4614..b889f5ab46 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -139,6 +139,10 @@ void Scene::removeNode(SceneGraphNode* node, UpdateDependencies updateDeps) { } } +void Scene::addSceneLicense(SceneLicense license) { + _licenses.push_back(std::move(license)); +} + void Scene::updateDependencies() { sortTopologically(); } @@ -272,6 +276,11 @@ const std::vector& Scene::allSceneGraphNodes() const { return _topologicallySortedNodes; } +void Scene::writeSceneLicenseDocumentation(const std::string& path) const { + SceneLicenseWriter writer(_licenses); + writer.writeDocumentation(path); +} + std::string Scene::generateJson() const { std::function createJson = [&createJson](properties::PropertyOwner* owner) -> std::string diff --git a/src/scene/scenelicense.cpp b/src/scene/scenelicense.cpp new file mode 100644 index 0000000000..9718e11925 --- /dev/null +++ b/src/scene/scenelicense.cpp @@ -0,0 +1,94 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + const char* LicenseKeyName = "Name"; + const char* LicenseKeyAttribution = "Attribution"; + const char* LicenseKeyUrl = "URL"; + const char* LicenseKeyLicenseText = "License"; +} // namespace + +namespace openspace { + +documentation::Documentation SceneLicense::Documentation() { + using namespace documentation; + + return { + "License Information", + "core_license", + { + { + LicenseKeyName, + new StringVerifier, + Optional::No, + "A short, descriptive name for the license employed for this node." + }, + { + LicenseKeyAttribution, + new StringVerifier, + Optional::No, + "The organization that shall be attributed to the licensed content." + }, + { + LicenseKeyUrl, + new StringVerifier, + Optional::Yes, + "The URL pointing to the original license." + }, + { + LicenseKeyLicenseText, + new StringVerifier, + Optional::No, + "The full text of the license agreements." + } + } + }; +} + +SceneLicense::SceneLicense(const ghoul::Dictionary& dictionary, std::string m) + : module(std::move(m)) +{ + ghoul_assert(!module.empty(), "Module name must not be empty"); + + documentation::testSpecificationAndThrow(Documentation(), dictionary, "SceneLicense"); + + name = dictionary.value(LicenseKeyName); + attribution = dictionary.value(LicenseKeyAttribution); + dictionary.getValue(LicenseKeyUrl, url); + licenseText = dictionary.value(LicenseKeyLicenseText); +} + +} // namespace openspace diff --git a/src/scene/scenelicensewriter.cpp b/src/scene/scenelicensewriter.cpp new file mode 100644 index 0000000000..454ae4afbd --- /dev/null +++ b/src/scene/scenelicensewriter.cpp @@ -0,0 +1,82 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace { + const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/main.hbs"; + const char* SceneLicenseTemplateFilename = "${OPENSPACE_DATA}/web/scenelicense/scenelicense.hbs"; + const char* JsFilename = "${OPENSPACE_DATA}/web/scenelicense/script.js"; +} // namespace + +namespace openspace { + +SceneLicenseWriter::SceneLicenseWriter(const std::vector& licenses) + : DocumentationGenerator( + "Documentation", + "sceneLicenses", + { + { "sceneLicenseTemplate", SceneLicenseTemplateFilename }, + { "mainTemplate", MainTemplateFilename } + }, + JsFilename + ) + , _licenses(licenses) +{} + +std::string SceneLicenseWriter::generateJson() const { + std::stringstream json; + json << "["; + for (const SceneLicense& license : _licenses) { + json << "{"; + json << "\"module\": \"" << escapedJson(license.module) << "\", "; + json << "\"name\": \"" << escapedJson(license.name) << "\", "; + json << "\"attribution\": \"" << escapedJson(license.attribution) << "\", "; + json << "\"url\": \"" << escapedJson(license.url) << "\", "; + json << "\"licenseText\": \"" << escapedJson(license.licenseText) << "\""; + json << "}"; + + if (&license != &(_licenses.back())) { + json << ","; + } + } + + json << "]"; + + + std::string jsonString = ""; + for (const char& c : json.str()) { + if (c == '\'') { + jsonString += "\\'"; + } else { + jsonString += c; + } + } + + return jsonString; +} + +} // namespace openspace diff --git a/src/scene/sceneloader.cpp b/src/scene/sceneloader.cpp index 8f44613c5d..26568bda9f 100644 --- a/src/scene/sceneloader.cpp +++ b/src/scene/sceneloader.cpp @@ -40,6 +40,7 @@ namespace { const char* KeyPathScene = "ScenePath"; const char* KeyModules = "Modules"; const char* ModuleExtension = ".mod"; + const char* LicenseExtension = ".license"; //const char* KeyPathModule = "ModulePath"; //const char* RootNodeName = "Root"; @@ -97,6 +98,7 @@ std::unique_ptr SceneLoader::loadScene(const std::string& path) { std::vector keys = moduleDictionary.keys(); std::vector allNodes; + std::vector allLicenses; { // Inside loadDirectory the working directory is changed (for now), so we need @@ -112,8 +114,19 @@ std::unique_ptr SceneLoader::loadScene(const std::string& path) { std::replace(fullName.begin(), fullName.end(), '/', FileSys.PathSeparator); std::string path = FileSys.pathByAppendingComponent(modulesPath, fullName); - std::vector nodes = loadDirectory(path, state); - std::move(nodes.begin(), nodes.end(), std::back_inserter(allNodes)); + std::pair, std::vector> + nodes = loadDirectory(path, state); + + std::move( + nodes.first.begin(), + nodes.first.end(), + std::back_inserter(allNodes) + ); + std::move( + nodes.second.begin(), + nodes.second.end(), + std::back_inserter(allLicenses) + ); } } @@ -125,6 +138,10 @@ std::unique_ptr SceneLoader::loadScene(const std::string& path) { addLoadedNodes(*scene, std::move(allNodes)); + for (SceneLicense& l : allLicenses) { + scene->addSceneLicense(std::move(l)); + } + ghoul::Dictionary cameraDictionary; sceneDictionary.getValue(KeyCamera, cameraDictionary); LoadedCamera loadedCamera = loadCamera(cameraDictionary); @@ -145,7 +162,8 @@ std::unique_ptr SceneLoader::loadScene(const std::string& path) { return scene; } -std::vector SceneLoader::importDirectory(Scene& scene, const std::string& path) { +std::pair, std::vector> +SceneLoader::importDirectory(Scene& scene, const std::string& path) { lua_State* state = ghoul::lua::createNewLuaState(); OnExit( // Delete the Lua state at the end of the scope, no matter what. @@ -156,9 +174,11 @@ std::vector SceneLoader::importDirectory(Scene& scene, const st std::string absDirectoryPath = absPath(path); ghoul::filesystem::Directory oldDirectory = FileSys.currentDirectory(); - std::vector nodes = loadDirectory(path, state); + std::pair, std::vector> + nodes = loadDirectory(path, state); + FileSys.setCurrentDirectory(oldDirectory); - return addLoadedNodes(scene, std::move(nodes)); + return { addLoadedNodes(scene, std::move(nodes.first)), nodes.second }; } SceneGraphNode* SceneLoader::importNodeDictionary(Scene& scene, const ghoul::Dictionary& dict) { @@ -198,14 +218,15 @@ SceneLoader::LoadedCamera SceneLoader::loadCamera(const ghoul::Dictionary& camer } -std::vector SceneLoader::loadDirectory( +std::pair, std::vector> +SceneLoader::loadDirectory( const std::string& path, lua_State* luaState) { std::string::size_type pos = path.find_last_of(FileSys.PathSeparator); if (pos == std::string::npos) { LERROR("Error parsing directory name '" << path << "'"); - return std::vector(); + return {}; } std::string moduleName = path.substr(pos + 1); std::string moduleFile = FileSys.pathByAppendingComponent(path, moduleName) + ModuleExtension; @@ -218,9 +239,18 @@ std::vector SceneLoader::loadDirectory( FileSys.setCurrentDirectory(ghoul::filesystem::Directory(path)); // We have a module file, so it is a direct include. - return loadModule(moduleFile, luaState); + std::vector nodes = loadModule(moduleFile, luaState); + + std::vector licenses; + std::string licenseFile = FileSys.pathByAppendingComponent(path, moduleName) + LicenseExtension; + if (FileSys.fileExists(licenseFile)) { + licenses = loadLicense(licenseFile, moduleName); + } + + return { std::move(nodes), licenses }; } else { std::vector allLoadedNodes; + std::vector allLicenses; // If we do not have a module file, we have to include all subdirectories. using ghoul::filesystem::Directory; using std::string; @@ -230,14 +260,25 @@ std::vector SceneLoader::loadDirectory( if (!FileSys.directoryExists(directoryPath)) { LERROR("The directory " << directoryPath << " does not exist."); - return std::vector(); + return {}; } for (const string& subdirectory : directory.readDirectories()) { - std::vector loadedNodes = loadDirectory(subdirectory, luaState); - std::move(loadedNodes.begin(), loadedNodes.end(), std::back_inserter(allLoadedNodes)); + std::pair, std::vector> + loadedNodes = loadDirectory(subdirectory, luaState); + + std::move( + loadedNodes.first.begin(), + loadedNodes.first.end(), + std::back_inserter(allLoadedNodes) + ); + std::move( + loadedNodes.second.begin(), + loadedNodes.second.end(), + std::back_inserter(allLicenses) + ); } - return allLoadedNodes; + return { std::move(allLoadedNodes), std::move(allLicenses) }; } } @@ -309,6 +350,19 @@ std::vector SceneLoader::loadModule(const std::string& return loadedNodes; } +std::vector SceneLoader::loadLicense(const std::string& path, std::string module) { + ghoul::Dictionary licenseDictionary; + try { + ghoul::lua::loadDictionaryFromFile(path, licenseDictionary); + } catch (const ghoul::lua::LuaRuntimeException& e) { + LERRORC(e.component, e.message); + return {}; + } + + SceneLicense license(licenseDictionary, module); + return { license }; +} + std::vector SceneLoader::addLoadedNodes(Scene& scene, std::vector&& loadedNodes) { std::map existingNodes = scene.nodesByName(); std::map addedNodes;