From 1fbb9e8acf878894c3c75f3dc8782e9c7782ae55 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 23 Apr 2020 12:06:34 -0600 Subject: [PATCH] Completed code for detecting and storing changes made since startup --- include/openspace/engine/openspaceengine.h | 3 + include/openspace/properties/property.h | 7 + include/openspace/scene/assetloader.h | 14 ++ include/openspace/scene/assetmanager.h | 3 + include/openspace/scene/profile.h | 50 ++++- include/openspace/scene/profilefile.h | 27 ++- src/engine/openspaceengine.cpp | 11 +- src/properties/property.cpp | 4 + src/scene/assetloader.cpp | 18 +- src/scene/assetmanager.cpp | 8 + src/scene/profile.cpp | 203 +++++++++++++++++++-- src/scene/profilefile.cpp | 14 +- tests/profile/test_profile.cpp | 4 +- 13 files changed, 320 insertions(+), 46 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index b150d594d1..3e9a86eb80 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___OPENSPACEENGINE___H__ #include +#include #include #include #include @@ -76,6 +77,8 @@ public: const glm::mat4& projectionMatrix); void drawOverlays(); void postDraw(); + std::vector listOfAllAssetEvents(); + void resetAssetChangeTracking(); void resetPropertyChangeFlags(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier modifier); diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 0cfbbc9be0..779ef9fe42 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -495,6 +495,13 @@ public: */ virtual std::string generateAdditionalJsonDescription() const; + /** + * Returns whether or not the property value has changed. + * + * \return true if the property has changed + */ + bool hasChanged(); + /** * Reset the valChanged flag to an unchanged state, as if value has not been changed. */ diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index 374448644f..25ec440b4f 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___ASSETLOADER___H__ #include +#include #include #include #include @@ -169,10 +170,22 @@ public: */ void assetUnrequested(std::shared_ptr parent, std::shared_ptr child); + /** + * Retrieve a reference to vector list of all assets events, including require, + * request, and remove + */ + const std::vector& listOfAllAssetEvents() const; + + /** + * Clear lists of all assets that have been either requested, required, or removed + */ + void listOfAllAssetEvents_reset(); + private: std::shared_ptr require(const std::string& identifier); std::shared_ptr request(const std::string& identifier); void unrequest(const std::string& identifier); + void addToProfileTracking(std::string asset, Profile::AssetEventType type); void setUpAssetLuaTable(Asset* asset); void tearDownAssetLuaTable(Asset* asset); @@ -227,6 +240,7 @@ private: _onDependencyDeinitializationFunctionRefs; int _assetsTableRef; + std::vector _profileAssets; std::vector _profileAssetsRequired; std::vector _profileAssetsRequested; std::vector _profileAssetsRemoved; diff --git a/include/openspace/scene/assetmanager.h b/include/openspace/scene/assetmanager.h index d279219463..db010c7d02 100644 --- a/include/openspace/scene/assetmanager.h +++ b/include/openspace/scene/assetmanager.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___ASSETMANAGER___H__ #include +#include #include #include @@ -70,6 +71,8 @@ public: std::shared_ptr child) override; bool update(); + const std::vector& listOfAllAssetEvents() const; + void listOfAllAssetEvents_reset(); scripting::LuaLibrary luaLibrary(); private: diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 9bfabfde04..6ef18bf6c5 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -44,9 +44,23 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } - class Profile { public: + enum class AssetEventType { + require, + request, + remove + }; + const std::map AssetEventTypeString { + {AssetEventType::require, "required"}, + {AssetEventType::request, "requested"}, + {AssetEventType::remove, "removed"}, + }; + struct AssetEvent { + std::string name; + AssetEventType eventType; + }; + /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. @@ -61,7 +75,7 @@ public: * \param outFilePath The output file path that will be written with the converted * contents (in an .asset file) */ - void convertToAssetFile(const std::string inProfilePath, + void convertToSceneFile(const std::string inProfilePath, const std::string outFilePath); /** @@ -70,7 +84,7 @@ public: * \param pf The profileFile object to be converted * \return The full string contents of scene/asset equivalent of the profile file. */ - std::string convertToAsset(ProfileFile& pf); + std::string convertToScene(ProfileFile& pf); /** * Returns the Lua library that contains all Lua functions available to provide @@ -80,14 +94,30 @@ public: static scripting::LuaLibrary luaLibrary(); private: - std::string convertToAsset_assets(ProfileFile& pf); - std::string convertToAsset_modules(ProfileFile& pf); - std::string convertToAsset_properties(ProfileFile& pf); - std::string convertToAsset_markNodes(ProfileFile& pf); - std::string convertToAsset_keybindings(ProfileFile& pf); - std::string convertToAsset_time(ProfileFile& pf); - std::string convertToAsset_camera(ProfileFile& pf); + struct AllAssetDetails { + std::vector base; + std::vector changed; + }; + std::string convertToScene_assets(ProfileFile& pf); + std::string convertToScene_modules(ProfileFile& pf); + std::string convertToScene_properties(ProfileFile& pf); + std::string convertToScene_markNodes(ProfileFile& pf); + std::string convertToScene_keybindings(ProfileFile& pf); + std::string convertToScene_time(ProfileFile& pf); + std::string convertToScene_camera(ProfileFile& pf); + + std::vector modifyAssetsToReflectChanges(ProfileFile& pf); + void parseAssetFileLines(std::vector& results, ProfileFile& pf); + void handleChangedRequire(std::vector& base, std::string asset); + void handleChangedRequest(std::vector& base, std::string asset); + void handleChangedRemove(std::vector& base, std::string asset); + void addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf); + void modifyPropertiesToReflectChanges(ProfileFile& pf); + std::vector getNodesThatHaveChangedProperties( + ProfileFile& pf); + void addCurrentTimeToProfileFile(ProfileFile& pf); + void addCurrentCameraToProfileFile(ProfileFile& pf); }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 82cfa0facd..3b01d97e54 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -92,6 +92,8 @@ const std::string header_MarkNodes = "#MarkNodes"; class ProfileFile { public: + using Lines = std::vector; + /** * Reads the contents of a profile file and populates vector containers for all * sections. This only pulls individual line entries into their proper sections; @@ -157,6 +159,11 @@ public: */ void addAssetLine(const std::string line); + /** + * Clears all asset entries + */ + void clearAssets(); + /** * Adds a new property set command to the list of property settings to be * performed at startup. The format for a property set command line is defined by @@ -213,28 +220,28 @@ public: * comment header for notes on the syntax of each entry. * \return The vector of asset lines */ - std::vector assets() const; + Lines assets() const; /** * Returns the vector of OpenSpace property set commands included in this profile. * See addPropertyLine comment header for notes on the syntax of each entry. * \return The vector of property set commands */ - std::vector properties() const; + Lines properties() const; /** * Returns the vector of OpenSpace keybinding shortcut definitions included in this * profile. See addKeybindingLine comment header for syntax notes of each entry. * \return The vector of keybinding shortcut definitions */ - std::vector keybindings() const; + Lines keybindings() const; /** * Returns the vector of OpenSpace scenegraph nodes marked as 'interesting'. * See addMarkNodesLine comment header for syntax notes of each entry. * \return The vector of nodes to be marked as interesting. */ - std::vector markNodes() const; + Lines markNodes() const; /** * Splits a tab-delimited line (of any type) into a vector with individual string @@ -245,6 +252,8 @@ public: */ size_t splitByTab(std::string line, std::vector& result); + + private: std::string errorString(std::string message); void clearAllFields(); @@ -272,11 +281,11 @@ private: std::string _version; std::string _time; std::string _camera; - std::vector _modules; - std::vector _assets; - std::vector _properties; - std::vector _keybindings; - std::vector _markNodes; + Lines _modules; + Lines _assets; + Lines _properties; + Lines _keybindings; + Lines _markNodes; }; } // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 5f04e66c2a..f825c45370 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -306,7 +306,7 @@ void OpenSpaceEngine::initialize() { std::string outputAsset = outputScenePath + "/" + global::configuration.profile + ".asset"; - global::profile.convertToAssetFile(inputProfile, outputAsset); + global::profile.convertToSceneFile(inputProfile, outputAsset); // Set asset name to that of the profile because a new scene file will be // created with that name, and also because the profile name will override @@ -1276,12 +1276,21 @@ void OpenSpaceEngine::postDraw() { if (_isFirstRenderingFirstFrame) { global::windowDelegate.setSynchronization(true); resetPropertyChangeFlags(); + resetAssetChangeTracking(); _isFirstRenderingFirstFrame = false; } LTRACE("OpenSpaceEngine::postDraw(end)"); } +void OpenSpaceEngine::resetAssetChangeTracking() { + global::openSpaceEngine._assetManager->listOfAllAssetEvents_reset(); +} + +std::vector OpenSpaceEngine::listOfAllAssetEvents() { + return global::openSpaceEngine._assetManager->listOfAllAssetEvents(); +} + void OpenSpaceEngine::resetPropertyChangeFlags() { ZoneScoped diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 5a00032616..1bedc86ac7 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -312,6 +312,10 @@ void Property::notifyDeleteListeners() { } } +bool Property::hasChanged() { + return valChanged; +} + void Property::resetToUnchanged() { valChanged = false; } diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 9439ea805a..9981ee4f05 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -444,7 +444,7 @@ std::shared_ptr AssetLoader::require(const std::string& identifier) { std::shared_ptr asset = getAsset(identifier); std::shared_ptr dependant = _currentAsset; dependant->require(asset); - _profileAssetsRequired.push_back(asset->assetFilePath()); + addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::require); return asset; } @@ -453,10 +453,15 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { std::shared_ptr parent = _currentAsset; parent->request(asset); assetRequested(parent, asset); - _profileAssetsRequested.push_back(asset->assetFilePath()); + addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::request); return asset; } +void AssetLoader::addToProfileTracking(std::string asset, Profile::AssetEventType type) { + Profile::AssetEvent pa = {asset, type}; + _profileAssets.push_back(pa); +} + void AssetLoader::unrequest(const std::string& identifier) { std::shared_ptr asset = has(identifier); std::shared_ptr parent = _currentAsset; @@ -484,6 +489,7 @@ void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset); unrequest(identifier); _profileAssetsRemoved.push_back(identifier); + addToProfileTracking(identifier, Profile::AssetEventType::remove); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { @@ -810,4 +816,12 @@ void AssetLoader::assetUnrequested(std::shared_ptr parent, } } +const std::vector& AssetLoader::listOfAllAssetEvents() const { + return _profileAssets; +} + +void AssetLoader::listOfAllAssetEvents_reset() { + _profileAssets.clear(); +} + } // namespace openspace diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index e64409fadd..d9d8e5e12e 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -121,6 +121,14 @@ std::shared_ptr AssetManager::rootAsset() { return _assetLoader->rootAsset(); } +const std::vector& AssetManager::listOfAllAssetEvents() const { + return _assetLoader->listOfAllAssetEvents(); +} + +void AssetManager::listOfAllAssetEvents_reset() { + _assetLoader->listOfAllAssetEvents_reset(); +} + scripting::LuaLibrary AssetManager::luaLibrary() { return { "asset", diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 57bb85fd89..e42934b4e5 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -27,20 +27,26 @@ #include #include #include +#include #include +#include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include #include #include #include +#include #include "profile_lua.inl" @@ -59,9 +65,172 @@ void Profile::saveCurrentSettingsToProfile(std::string filename) { LERROR(errorMessage); } std::string initProfile = global::configuration.profile; + ProfileFile pf; + pf.readFromFile(initProfile); + std::vector ass = modifyAssetsToReflectChanges(pf); + addAssetsToProfileFile(ass, pf); + modifyPropertiesToReflectChanges(pf); + addCurrentTimeToProfileFile(pf); + addCurrentCameraToProfileFile(pf); } -void Profile::convertToAssetFile(const std::string inProfilePath, +std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { + std::vector a; + parseAssetFileLines(a, pf); + AllAssetDetails assetDetails; + + assetDetails.base = a; + assetDetails.changed = global::openSpaceEngine.listOfAllAssetEvents(); + + for (AssetEvent event : assetDetails.changed) { + if (event.eventType == AssetEventType::require) { + handleChangedRequire(assetDetails.base, event.name); + } + else if (event.eventType == AssetEventType::request) { + handleChangedRequest(assetDetails.base, event.name); + } + else if (event.eventType == AssetEventType::remove) { + handleChangedRemove(assetDetails.base, event.name); + } + } + return assetDetails.base; +} + +void Profile::handleChangedRequire(std::vector& base, std::string asset) { + for (auto b : base) { + if (b.name == asset && b.eventType == AssetEventType::request) { + base.push_back({asset, AssetEventType::require}); + } + } +} + +void Profile::handleChangedRequest(std::vector& base, std::string asset) { + bool addThisAsset = true; + std::vector::iterator f; + f = find_if(base.begin(), base.end(), [asset](AssetEvent ae) + { return (ae.name == asset); } ); + if (f != base.end()) { + addThisAsset = false; + } + + if (addThisAsset) { + AssetEvent ae = {asset, AssetEventType::request}; + base.push_back(ae); + } +} + +void Profile::handleChangedRemove(std::vector& base, std::string asset) { + std::vector::iterator f; + f = remove_if(base.begin(), base.end(), [asset](AssetEvent ae) + { return (ae.name == asset); } ); +} + +void Profile::addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf) +{ + pf.clearAssets(); + for (AssetEvent a : allAssets) { + std::string entry = a.name + "\t" + AssetEventTypeString.at(a.eventType); + pf.addAssetLine(entry); + } +} + +void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { + std::vector elements; + AssetEvent a; + + for (std::string line : pf.assets()) { + pf.splitByTab(line, elements); + + if (a.name.empty()) { + LERROR("Error in parsing asset file line '" + line + + "'. Asset name is needed (field 1/2)."); + } + else { + a.name = elements[0]; + } + + if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { + a.eventType = AssetEventType::require; + } + else if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { + a.eventType = AssetEventType::request; + } + else if (elements[1] == "") { + a.eventType = AssetEventType::request; + } + else { + LERROR("Error in parsing asset file line '" + line + + "'. Invalid required param (field 2/2)."); + } + + results.push_back(a); + } +} + +void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { + std::vector changedProps + = getNodesThatHaveChangedProperties(pf); + std::string newLine; + + for (auto prop : changedProps) { + newLine = "setPropertyValueSingle\t"; + newLine += prop->identifier() + "\t"; + newLine += prop->getStringValue() + "\n"; + pf.addPropertyLine(newLine); + } +} + +std::vector Profile::getNodesThatHaveChangedProperties( + ProfileFile& pf) +{ + ZoneScoped + + std::vector nodes = + global::renderEngine.scene()->allSceneGraphNodes(); + std::vector changedProps; + + for (auto n : nodes) { + std::vector props = n->properties(); + for (auto p : props) { + if (p->hasChanged()) { + changedProps.push_back(p); + } + } + } + return changedProps; +} + +void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) { + std::string t = global::timeManager.time().UTC(); + std::string update = "absolute\t" + t + "\n"; + pf.updateTime(update); +} + +void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { + std::string update = "setNavigationState\t"; + interaction::NavigationHandler::NavigationState nav; + nav = global::navigationHandler.navigationState(); + update += nav.anchor + "\t"; + update += nav.aim + "\t"; + update += nav.referenceFrame + "\t"; + update += std::to_string(nav.position.x) + ","; + update += std::to_string(nav.position.y) + ","; + update += std::to_string(nav.position.z) + "\t"; + if (nav.up.has_value()) { + glm::dvec3 u = nav.up.value(); + //glm::dvec3 u = static_cast(nav.up.value()); + update += std::to_string(u.x) + ","; + update += std::to_string(u.y) + ","; + update += std::to_string(u.z); + } + update += "\t"; + update += std::to_string(nav.yaw) + "\t"; + update += std::to_string(nav.pitch) + "\n"; + + pf.updateCamera(update); +} + +void Profile::convertToSceneFile(const std::string inProfilePath, const std::string outFilePath) { ProfileFile pf; @@ -77,7 +246,7 @@ void Profile::convertToAssetFile(const std::string inProfilePath, } try { - outFile << convertToAsset(pf); + outFile << convertToScene(pf); } catch (std::ofstream::failure& e) { LERROR("Data write error to file: " + outFilePath); @@ -91,24 +260,24 @@ void Profile::convertToAssetFile(const std::string inProfilePath, } } -std::string Profile::convertToAsset(ProfileFile& pf) { +std::string Profile::convertToScene(ProfileFile& pf) { std::string result; - result += convertToAsset_modules(pf) + "\n"; - result += convertToAsset_assets(pf) + "\n"; - result += convertToAsset_keybindings(pf) + "\n"; + result += convertToScene_modules(pf) + "\n"; + result += convertToScene_assets(pf) + "\n"; + result += convertToScene_keybindings(pf) + "\n"; result += "asset.onInitialize(function ()\n"; - result += convertToAsset_time(pf) + "\n"; + result += convertToScene_time(pf) + "\n"; result += " sceneHelper.bindKeys(Keybindings)\n\n"; - result += convertToAsset_markNodes(pf) + "\n"; - result += convertToAsset_properties(pf) + "\n"; - result += convertToAsset_camera(pf); + result += convertToScene_markNodes(pf) + "\n"; + result += convertToScene_properties(pf) + "\n"; + result += convertToScene_camera(pf); result += "end)\n"; return result; } -std::string Profile::convertToAsset_modules(ProfileFile& pf) { +std::string Profile::convertToScene_modules(ProfileFile& pf) { std::string result; std::vector fields; @@ -131,7 +300,7 @@ std::string Profile::convertToAsset_modules(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_assets(ProfileFile& pf) { +std::string Profile::convertToScene_assets(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -166,7 +335,7 @@ std::string Profile::convertToAsset_assets(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_properties(ProfileFile& pf) { +std::string Profile::convertToScene_properties(ProfileFile& pf) { std::string result; std::vector fields; @@ -190,7 +359,7 @@ std::string Profile::convertToAsset_properties(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { +std::string Profile::convertToScene_keybindings(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -213,7 +382,7 @@ std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { +std::string Profile::convertToScene_markNodes(ProfileFile& pf) { std::string result; if (pf.markNodes().size() > 0) { @@ -226,7 +395,7 @@ std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_time(ProfileFile& pf) { +std::string Profile::convertToScene_time(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -248,7 +417,7 @@ std::string Profile::convertToAsset_time(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_camera(ProfileFile& pf) { +std::string Profile::convertToScene_camera(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index b2c4251cb4..345a258f9c 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -241,23 +241,23 @@ std::string ProfileFile::camera() const { return _camera; } -std::vector ProfileFile::modules() const { +ProfileFile::Lines ProfileFile::modules() const { return _modules; } -std::vector ProfileFile::assets() const { +ProfileFile::Lines ProfileFile::assets() const { return _assets; } -std::vector ProfileFile::properties() const { +ProfileFile::Lines ProfileFile::properties() const { return _properties; } -std::vector ProfileFile::keybindings() const { +ProfileFile::Lines ProfileFile::keybindings() const { return _keybindings; } -std::vector ProfileFile::markNodes() const { +ProfileFile::Lines ProfileFile::markNodes() const { return _markNodes; } @@ -472,4 +472,8 @@ void ProfileFile::addMarkNodesLine(const std::string line) { _markNodes.push_back(line); } +void ProfileFile::clearAssets() { + _assets.clear(); +} + } // namespace openspace diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 62389a275b..12fdc5a94c 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -48,7 +48,7 @@ TEST_CASE("profile: Convert profileFile to asset", "[profile]") { Profile p; REQUIRE_NOTHROW( - p.convertToAsset(pf) + p.convertToScene(pf) ); } @@ -58,7 +58,7 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") { Profile p; std::string result; REQUIRE_NOTHROW( - result = p.convertToAsset(pf) + result = p.convertToScene(pf) ); std::string testing, comparing;