From af8bec1441727b1e224978db039ca24f9a7eecb2 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 14 Sep 2017 20:16:51 +0200 Subject: [PATCH] Prepare for data sync --- assets/assethelper.asset | 9 + assets/planets/earth/planet.asset | 13 +- include/openspace/engine/openspaceengine.h | 12 +- include/openspace/scene/asset.h | 127 ++++ include/openspace/scene/assetloader.h | 153 ++--- include/openspace/util/asynchttprequest.h | 136 ++++ .../openspace/util/resourcesynchronization.h | 9 +- include/openspace/util/resourcesynchronizer.h | 40 ++ modules/globebrowsing/globebrowsingmodule.cpp | 3 + modules/sync/syncmodule.cpp | 6 +- modules/sync/syncmodule.h | 2 +- modules/sync/syncs/httpsynchronization.cpp | 27 +- modules/sync/syncs/httpsynchronization.h | 13 +- src/CMakeLists.txt | 5 + src/engine/openspaceengine.cpp | 15 +- src/scene/asset.cpp | 288 ++++++++ src/scene/assetloader.cpp | 630 ++++++------------ src/scene/assetloader_lua.inl | 22 +- src/scene/sceneloader.cpp | 11 +- .../util/resourcesynchronizer.cpp | 8 +- 20 files changed, 925 insertions(+), 604 deletions(-) create mode 100644 include/openspace/scene/asset.h create mode 100644 include/openspace/util/asynchttprequest.h create mode 100644 include/openspace/util/resourcesynchronizer.h create mode 100644 src/scene/asset.cpp rename modules/sync/syncs/resourcesynchronization.h => src/util/resourcesynchronizer.cpp (87%) diff --git a/assets/assethelper.asset b/assets/assethelper.asset index 08c8e4d329..9cede8199f 100644 --- a/assets/assethelper.asset +++ b/assets/assethelper.asset @@ -1,3 +1,12 @@ +asset.registerSynchronizations = function (asset, syncs) + local oldSync = asset.onSync; + asset.onSynchronize = function() + for i, sync in ipairs(syncs) do + openspace.addSynchronization(asset, sync) + end + end +end + asset.registerSceneGraphNodes = function (sceneAsset, nodes) local oldInit = sceneAsset.onInitialize; sceneAsset.onInitialize = function () diff --git a/assets/planets/earth/planet.asset b/assets/planets/earth/planet.asset index a10caf699f..c2f06a51b0 100644 --- a/assets/planets/earth/planet.asset +++ b/assets/planets/earth/planet.asset @@ -1,15 +1,12 @@ local assetHelper = asset.import("assethelper") local transforms = asset.import("./transforms") -asset.data = { - FileRequest = { - { - Destination = asset.syncedResource("textures"), - Identifier = "earth_textures", - Version = 2 - } +assetHelper.registerSynchronization(asset, { + { + Type = "HTTPSynchronization", + --- todo... } -} +}) asset.Earth = { Name = "Earth", diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 0feeebcd8c..a31aebefdb 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -42,6 +42,7 @@ namespace ghoul::fontrendering { class FontManager; } namespace openspace { +class AssetLoader; class ConfigurationManager; class DownloadManager; class GUI; @@ -50,14 +51,13 @@ class ModuleEngine; class NetworkEngine; class ParallelConnection; class RenderEngine; -class SettingsEngine; -class VirtualPropertyManager; +class ResourceSynchronizer; class Scene; -class AssetLoader; class SceneLoader; - class SyncEngine; +class SettingsEngine; class TimeManager; +class VirtualPropertyManager; class WindowWrapper; namespace interaction { @@ -122,6 +122,7 @@ public: TimeManager& timeManager(); WindowWrapper& windowWrapper(); AssetLoader& assetLoader(); + ResourceSynchronizer& resourceSynchronizer(); ghoul::fontrendering::FontManager& fontManager(); interaction::NavigationHandler& navigationHandler(); interaction::KeyBindingManager& keyBindingManager(); @@ -201,6 +202,7 @@ private: std::unique_ptr _fontManager; std::unique_ptr _navigationHandler; std::unique_ptr _keyBindingManager; + std::unique_ptr _resourceSynchronizer; std::unique_ptr _scriptEngine; std::unique_ptr _scriptScheduler; std::unique_ptr _virtualPropertyManager; diff --git a/include/openspace/scene/asset.h b/include/openspace/scene/asset.h new file mode 100644 index 0000000000..274be0f726 --- /dev/null +++ b/include/openspace/scene/asset.h @@ -0,0 +1,127 @@ +/***************************************************************************************** + * * + * 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___ASSET___H__ +#define __OPENSPACE_CORE___ASSET___H__ + +#include +#include +#include + +#include +#include +#include + +namespace openspace { + +class AssetLoader; + +class Asset : public properties::PropertyOwner { +public: + struct Optional : public properties::PropertyOwner { + public: + Optional(Asset* asset, Asset* owner, bool enabled = false); + private: + properties::BoolProperty _enabled; + Asset* asset; + }; + + enum class ReadyState : unsigned int { + Loaded, + Synchronizing, + Synchronized, + Initialized + }; + + /** + * Root asset constructor + */ + Asset(AssetLoader* loader, ghoul::filesystem::Directory directory); + + /** + * Dependency or Optional constructor + */ + Asset(AssetLoader* loader, ghoul::filesystem::Directory baseDirectory, std::string assetPath); + + std::string id(); + std::string assetFilePath(); + std::string assetName(); + std::string assetDirectory(); + AssetLoader* loader(); + std::string syncDirectory(); + ReadyState readyState(); + bool isInitReady() const; + void initialize(); + void deinitialize(); + + bool hasDependency(Asset* asset); + void addDependency(Asset* asset); + void removeDependency(Asset* asset); + void removeDependency(const std::string& assetId); + + bool hasDependants(); + bool hasInitializedDependants(); + + bool hasOptional(Asset* asset); + bool setOptionalEnabled(Asset* asset, bool enabled); + bool addOptional(Asset* asset, bool enabled); + bool removeOptional(Asset* asset); + + void dependantDidInitialize(Asset* dependant); + void dependantWillDeinitialize(Asset* dependant); + + void optionalDidInitialize(Asset* optional); + void optionalWillDeinitialize(Asset* optional); + + bool shouldSynchronize(); + bool shouldInitialize(); +private: + std::string resolveLocalResource(std::string resourceName); + std::string resolveSyncedResource(std::string resourceName); + + ReadyState _readyState; + AssetLoader* _loader; + + // Base name of .asset file + std::string _assetName; + + // Asbolute path to directory with the .asset file + std::string _assetDirectory; + + // Asset dependencies + std::vector _dependencies; + + // Asset dependants + std::vector _dependants; + + // Optional sub-assets + std::vector _optionalAssets; + + // Assets that refers to this asset as an optional + std::vector _optionalOwners; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___ASSET__H__ diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index c08b312e63..95d590ca08 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -28,9 +28,7 @@ #include #include -#include -#include -#include +#include #include #include @@ -43,109 +41,79 @@ namespace openspace { +class Asset; + namespace assetloader { -int importAsset(lua_State* state); -int importAssetToggle(lua_State* state); +int importDependency(lua_State* state); +int importOptional(lua_State* state); int resolveLocalResource(lua_State* state); int resolveSyncedResource(lua_State* state); } // namespace assetloader class AssetLoader { public: - class Asset; + /** + * Constructor + */ + AssetLoader( + ghoul::lua::LuaState& luaState, + ResourceSynchronizer& resourceSynchronizer, + std::string assetRoot, + std::string syncRoot + ); - using InitializationRequirement = ghoul::Boolean; - using Dependency = std::pair; - - class DependencyToggle : public properties::PropertyOwner { - public: - DependencyToggle(Asset* dependency, Asset* dependant, bool enabled = false); - private: - properties::BoolProperty _enabled; - Asset* _dependant; - Asset* _dependency; - }; - - class Asset : public properties::PropertyOwner { - public: - Asset(AssetLoader* loader, ghoul::filesystem::Directory directory); - Asset(AssetLoader* loader, ghoul::filesystem::Directory baseDirectory, std::string assetPath); - std::string id(); - std::string assetFilePath(); - std::string assetName(); - std::string assetDirectory(); - AssetLoader* loader(); - ghoul::Dictionary syncDictionary(); - std::string syncDirectory(); - bool isInitialized(); - bool hasLuaTable(); - void initialize(); - void deinitialize(); - - bool hasDependency(Asset* asset, InitializationRequirement initReq); - void addDependency(Asset* asset, bool togglableInitReq, InitializationRequirement initReq); - void setInitializationRequirement(Asset* dependency, InitializationRequirement initReq); - void removeDependency(Asset* asset); - void removeDependency(const std::string& assetId); - void dependantDidInitialize(Asset* dependant); - void dependantWillDeinitialize(Asset* dependant); - - bool hasInitializedDependants(InitializationRequirement initReq); - bool hasDependant(InitializationRequirement initReq); - private: - std::string resolveLocalResource(std::string resourceName); - std::string resolveSyncedResource(std::string resourceName); - - // lua methods - friend int assetloader::resolveLocalResource(lua_State* state); - int resolveLocalResourceLua(); - - friend int assetloader::resolveSyncedResource(lua_State* state); - int resolveSyncedResourceLua(); - - bool _hasLuaTable; - bool _initialized; - AssetLoader* _loader; - - // Base name of .asset file - std::string _assetName; - - // Asbolute path to directory with the .asset file - std::string _assetDirectory; - - // Other assets that this asset depend on - std::vector _dependencies; - - // Other assets that depend on this asset - std::vector _dependants; - - std::vector> _dependencyToggles; - // Other assets that this asset may toggle - //std::vector _toggles; - - // Other assets that may toggle this asset - //std::vector _togglers; - }; - - AssetLoader(ghoul::lua::LuaState* _luaState, std::string assetRoot, std::string syncRoot); + /** + * Destructor + */ ~AssetLoader() = default; + /** + * Import an asset + * Add the asset as an optional on the root asset + */ + void importAsset(const std::string& identifier); - void loadAsset(const std::string& identifier); - void unloadAsset(const std::string& identifier); + /** + * Unimport an asset + * Remove the asset as an optional on the root asset + */ + void unimportAsset(const std::string& identifier); + /** + * Return the lua library + */ scripting::LuaLibrary luaLibrary(); + /** + * Return the lua state + */ ghoul::lua::LuaState* luaState(); - ghoul::filesystem::Directory currentDirectory(); + + /** + * Return the root asset + */ Asset* rootAsset(); - const std::string& syncRoot(); + + /** + * Return the sync root directory + */ + const std::string& syncRootDirectory(); + + + void callOnInitialize(Asset* asset); + + void callOnDeinitialize(Asset* asset); + + void callOnDependantInitialize(Asset* asset, Asset* dependant); + + void callOnDependantDeinitialize(Asset* asset, Asset* dependant); private: - Asset* importAsset( - const std::string& identifier, - bool togglableInitializationRequirement = false, - bool toggleOn = true); + Asset* importDependency(const std::string& identifier); + Asset* importOptional(const std::string& identifier, bool enabled = true); + Asset* loadAsset(std::string name); + Asset* getAsset(std::string name); + ghoul::filesystem::Directory currentDirectory(); void pushAsset(Asset* asset); void popAsset(); @@ -155,10 +123,11 @@ private: std::map> _importedAssets; std::vector _assetStack; - std::string _syncRoot; + ResourceSynchronizer* _resourceSynchronizer; + std::string _syncRootDirectory; - friend int assetloader::importAsset(lua_State* state); - friend int assetloader::importAssetToggle(lua_State* state); + friend int assetloader::importDependency(lua_State* state); + friend int assetloader::importOptional(lua_State* state); int importAssetLua( std::string assetName, bool togglableInitializationRequirement = false, diff --git a/include/openspace/util/asynchttprequest.h b/include/openspace/util/asynchttprequest.h new file mode 100644 index 0000000000..4505906cf4 --- /dev/null +++ b/include/openspace/util/asynchttprequest.h @@ -0,0 +1,136 @@ +/***************************************************************************************** +* * +* 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___ASYNCHTTPREQUEST___H__ +#define __OPENSPACE_CORE___ASYNCHTTPREQUEST___H__ + +#include +#include + +namespace openspace { + +class AsncHttpRequestData { +public: + std::chrono::system_clock::time_point startTime(); + std::chrono::system_clock::time_point finishTime(); +private: + std::chrono::system_clock::time_point _startTime; + std::chrono::system_clock::time_point _finishTime; +}; + +class AsyncHttpRequest { +public: + enum class ReadyState : unsigned int { + Unsent, + Loading, + Done + }; + + using StateChangeCallback = std::function; + using ProgressCallback = std::function; + using DataCallback = std::function; + + AsyncHttpRequest( + std::string url, + DataCallback dataCallback); + ~AsyncHttpRequest(); + + virtual std::future start( + StateChangeCallback stateChangeCallback, + ProgressCallback progressCallback); + void wait(); + + std::chrono::system_clock::duration timeElapsed(); + std::chrono::system_clock::duration estimatedTimeRemaining(); + float progress(); + ReadyState readyState(); +private: + std::chrono::system_clock::time_point startTime; + float _progress; +}; + +////// + +class AsncHttpDownloadData : public AsncHttpRequestData { +public: + std::string url(); +private: + std::string _url; +}; + +class AsyncHttpDownload : public AsyncHttpRequest { +public: + AsyncHttpDownload( + std::string url, + std::string path); + virtual ~AsyncHttpDownload(); + + /*std::future start( + StateChangeCallback stateChangeCallback, + ProgressCallback progressCallback) override;*/ +}; + +//// + +class AsyncHttpReadData : public AsncHttpRequestData { +public: + std::vector& buffer(); +private: + std::vector _buffer; +}; + +class AsyncHttpRead : public AsyncHttpRequest { +public: + AsyncHttpRead(std::string url); + ~AsyncHttpRead(); + /*std::future start( + StateChangeCallback stateChangeCallback, + ProgressCallback progressCallback) override;*/ +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___ASYNCHTTPREQUEST___H__ + +/* +// start +std::ostream file(); +AsyncHttpDownload d(url, file); +std::future data = d->start(progressCallback, progressCallback); + +// in event loop +AsyncHttpRequest::ReadyState status = d.readyState(); +if (status == AsyncHttpRequest::ReadyState::Loading) { + float progress = d.progress(); + // update some progress bar.. +} + + + + +// usage: + +HTTPDownload (); + +*/ diff --git a/include/openspace/util/resourcesynchronization.h b/include/openspace/util/resourcesynchronization.h index 43e0592d67..ff24b87dd9 100644 --- a/include/openspace/util/resourcesynchronization.h +++ b/include/openspace/util/resourcesynchronization.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -32,12 +32,6 @@ namespace openspace { -struct SynchronizationProduct { - ghoul::filesystem::Directory destination; - std::string folderName; -}; - -using SynchronizationJob = Job; class ResourceSynchronization { public: @@ -45,7 +39,6 @@ public: ResourceSynchronization() = default; virtual bool needsSync() = 0; - virtual std::shared_ptr createSynchronizationJob() = 0; }; diff --git a/include/openspace/util/resourcesynchronizer.h b/include/openspace/util/resourcesynchronizer.h new file mode 100644 index 0000000000..913fd6561a --- /dev/null +++ b/include/openspace/util/resourcesynchronizer.h @@ -0,0 +1,40 @@ +/***************************************************************************************** + * * + * 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___RESOURCESYNCHRONIZER___H__ +#define __OPENSPACE_CORE___RESOURCESYNCHRONIZER___H__ + +#include +#include + +namespace openspace { + +class ResourceSynchronizer { + +}; + + +} // namespace openspace + +#endif // __OPENSPACE_CORE___RESOURCESYNCHRONIZER___H__ diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 7ecc0aa713..20c20e5c94 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -240,6 +240,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { { "loadWMSCapabilities", &globebrowsing::luascriptfunctions::loadWMSCapabilities, + {}, "string, string, string", "Loads and parses the WMS capabilities xml file from a remote server. " "The first argument is the name of the capabilities that can be used to " @@ -250,6 +251,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { { "removeWMSServer", &globebrowsing::luascriptfunctions::removeWMSServer, + {}, "string", "Removes the WMS server identified by the first argument from the list " "of available servers. The parameter corrsponds to the first argument in " @@ -258,6 +260,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { { "capabilitiesWMS", &globebrowsing::luascriptfunctions::capabilities, + {}, "string", "Returns an array of tables that describe the available layers that are " "supported by the WMS server identified by the provided name. The 'URL'" diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index 611a5de479..d933645a57 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -39,7 +39,9 @@ namespace openspace { -SyncModule::SyncModule() : OpenSpaceModule(Name) {} +SyncModule::SyncModule() + : OpenSpaceModule(Name) +{} void SyncModule::internalInitialize() { diff --git a/modules/sync/syncmodule.h b/modules/sync/syncmodule.h index 06a0127510..1e98290b96 100644 --- a/modules/sync/syncmodule.h +++ b/modules/sync/syncmodule.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * diff --git a/modules/sync/syncs/httpsynchronization.cpp b/modules/sync/syncs/httpsynchronization.cpp index 4bd784cc51..75f08bb9f1 100644 --- a/modules/sync/syncs/httpsynchronization.cpp +++ b/modules/sync/syncs/httpsynchronization.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -24,40 +24,23 @@ #include "httpsynchronization.h" +#include + + namespace openspace { HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict) : openspace::ResourceSynchronization() { - + } bool HttpSynchronization::needsSync() { return true; } -std::shared_ptr HttpSynchronization::createSynchronizationJob() { - return std::make_shared(); -} - documentation::Documentation HttpSynchronization::Documentation() { return {}; } -HttpSynchronizationJob::HttpSynchronizationJob() { - -} - -HttpSynchronizationJob::~HttpSynchronizationJob() { - -} - -void HttpSynchronizationJob::execute() { - -} - -std::shared_ptr HttpSynchronizationJob::product() { - return nullptr; -} - } // namespace openspace diff --git a/modules/sync/syncs/httpsynchronization.h b/modules/sync/syncs/httpsynchronization.h index 5af19e7f57..dd7e289f67 100644 --- a/modules/sync/syncs/httpsynchronization.h +++ b/modules/sync/syncs/httpsynchronization.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -36,19 +36,10 @@ class HttpSynchronization : public ResourceSynchronization { public: HttpSynchronization(const ghoul::Dictionary& dict); bool needsSync() override; - std::shared_ptr createSynchronizationJob() override; + void start(); static documentation::Documentation Documentation(); }; -class HttpSynchronizationJob : public SynchronizationJob { -public: - HttpSynchronizationJob(); - virtual ~HttpSynchronizationJob(); - - void execute() override; - std::shared_ptr product() override; -}; - } // namespace openspace #endif // __OPENSPACE_MODULE_SYNC___HTTPSYNCHRONIZATION___H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ed1c8a3b0..ade242ea74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/rendering/renderengine_lua.inl ${OPENSPACE_BASE_DIR}/src/rendering/screenspacerenderable.cpp ${OPENSPACE_BASE_DIR}/src/rendering/transferfunction.cpp + ${OPENSPACE_BASE_DIR}/src/scene/asset.cpp ${OPENSPACE_BASE_DIR}/src/scene/assetloader_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/assetloader.cpp ${OPENSPACE_BASE_DIR}/src/scene/translation.cpp @@ -153,6 +154,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/powerscaledscalar.cpp ${OPENSPACE_BASE_DIR}/src/util/powerscaledsphere.cpp ${OPENSPACE_BASE_DIR}/src/util/progressbar.cpp + ${OPENSPACE_BASE_DIR}/src/util/resourcesynchronizer.cpp ${OPENSPACE_BASE_DIR}/src/util/screenlog.cpp ${OPENSPACE_BASE_DIR}/src/util/spicemanager.cpp ${OPENSPACE_BASE_DIR}/src/util/spicemanager_lua.inl @@ -283,6 +285,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/screenspacerenderable.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/transferfunction.h + ${OPENSPACE_BASE_DIR}/include/openspace/scene/asset.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetloader.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/translation.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h @@ -311,6 +314,8 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/powerscaledscalar.h ${OPENSPACE_BASE_DIR}/include/openspace/util/powerscaledsphere.h ${OPENSPACE_BASE_DIR}/include/openspace/util/progressbar.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/resourcesynchronization.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/resourcesynchronizer.h ${OPENSPACE_BASE_DIR}/include/openspace/util/screenlog.h ${OPENSPACE_BASE_DIR}/include/openspace/util/spicemanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/syncbuffer.h diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index ce2b20e653..b5a8e0d666 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -54,11 +54,12 @@ #include #include -#include #include +#include +#include +#include #include #include -#include #include #include @@ -144,6 +145,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, , _networkEngine(new NetworkEngine) , _parallelConnection(new ParallelConnection) , _renderEngine(new RenderEngine) + , _resourceSynchronizer(new ResourceSynchronizer(8)) , _settingsEngine(new SettingsEngine) , _syncEngine(std::make_unique(4096)) , _timeManager(new TimeManager) @@ -409,7 +411,7 @@ void OpenSpaceEngine::create(int argc, char** argv, // Set up asset loader and scene loader _engine->_assetLoader = std::make_unique( - OsEng.scriptEngine().luaState(), "${ASSETS}", "${SYNC}"); + *OsEng.scriptEngine().luaState(), OsEng.resourceSynchronizer(), "${ASSETS}", "${SYNC}"); _engine->_sceneLoader = std::make_unique(_engine->_assetLoader.get()); _engine->_globalPropertyNamespace->addPropertySubOwner(_engine->_assetLoader->rootAsset()); } @@ -1473,6 +1475,11 @@ AssetLoader & OpenSpaceEngine::assetLoader() { return *_assetLoader; } +ResourceSynchronizer & OpenSpaceEngine::resourceSynchronizer() { + ghoul_assert(_resourceSynchronizer, "Resource Synchronizer must not be nullptr"); + return *_resourceSynchronizer; +} + ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() { ghoul_assert(_fontManager, "Font Manager must not be nullptr"); return *_fontManager; diff --git a/src/scene/asset.cpp b/src/scene/asset.cpp new file mode 100644 index 0000000000..b539692788 --- /dev/null +++ b/src/scene/asset.cpp @@ -0,0 +1,288 @@ +/***************************************************************************************** + * * + * 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 + +namespace { + const char* _loggerCat = "Asset"; + + bool isRelative(std::string path) { + if (path.size() > 2) { + if (path[0] == '.' && path[1] == '/') return true; + } + if (path.size() > 3) { + if (path[0] == '.' && path[1] == '.' && path[2] == '/') return true; + } + return false; + }; +} + +namespace openspace { + +std::string Asset::resolveLocalResource(std::string resourceName) { + std::string currentAssetDirectory = assetDirectory(); + return currentAssetDirectory + ghoul::filesystem::FileSystem::PathSeparator + resourceName; +} + +std::string Asset::syncDirectory() { + std::string currentAssetDirectory = assetDirectory(); + std::string rootAssetDirectory = loader()->rootAsset()->assetDirectory(); + std::string relativePath = FileSys.relativePath(currentAssetDirectory, rootAssetDirectory); + + return loader()->syncRootDirectory() + + ghoul::filesystem::FileSystem::PathSeparator + + relativePath + + ghoul::filesystem::FileSystem::PathSeparator + + assetName(); +} + +Asset::ReadyState Asset::readyState() { + return _readyState; +} + +bool Asset::isInitReady() const { + // An asset is ready for initialization if it is synchronized + // and all its dependencies are ready for initialization. + if (_readyState != Asset::ReadyState::Synchronized) { + return false; + } + for (const auto& dependency : _dependencies) { + if (!dependency->isInitReady()) { + return false; + } + } + return true; +} + +void Asset::initialize() { + LDEBUG("Initializing asset " << id()); + if (_readyState == Asset::ReadyState::Initialized) { + return; + } + + if (!isInitReady()) { + // TODO: THROW + } + + // Initialize dependencies + for (auto& dependency : _dependencies) { + dependency->initialize(); + } + + _readyState = Asset::ReadyState::Initialized; + + // Call onInitialize in Lua + loader()->callOnInitialize(this); + + // Notify dependencies + for (auto& dependency : _dependencies) { + dependency->dependantDidInitialize(this); + } +} + +void Asset::deinitialize() { + if (_readyState != Asset::ReadyState::Initialized) { + return; + } + + // Notify dependencies + for (auto& dependency : _dependencies) { + dependency->dependantWillDeinitialize(this); + } + + // Call onDeinitialize in Lua + loader()->callOnDeinitialize(this); + + _readyState = Asset::ReadyState::Synchronized; + + // Make sure no dependencies are left dangling + for (auto& dependency : _dependencies) { + if (!dependency->hasInitializedDependants()) { + dependency->deinitialize(); + } + } +} + +std::string Asset::resolveSyncedResource(std::string resourceName) { + return syncDirectory() + + ghoul::filesystem::FileSystem::PathSeparator + + resourceName; +} + +Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory directory) + : PropertyOwner({ "RootAsset", "Root asset" }) + , _assetDirectory(directory) + , _loader(loader) + , _readyState(Asset::ReadyState::Loaded) +{} + +Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory baseDirectory, std::string assetPath) + : PropertyOwner({ assetPath, assetPath }) + , _readyState(Asset::ReadyState::Loaded) + , _loader(loader) +{ + if (isRelative(assetPath)) { + ghoul::filesystem::File assetFile = + static_cast(baseDirectory) + + ghoul::filesystem::FileSystem::PathSeparator + + assetPath + + "." + + AssetFileSuffix; + + _assetDirectory = assetFile.directoryName(); + _assetName = assetFile.baseName(); + } else { + std::string assetRoot = ghoul::filesystem::Directory(loader->rootAsset()->assetDirectory()); + ghoul::filesystem::File assetFile = + assetRoot + + ghoul::filesystem::FileSystem::PathSeparator + + assetPath + + "." + + AssetFileSuffix; + + _assetDirectory = assetFile.directoryName(); + _assetName = assetFile.baseName(); + } +} + +std::string Asset::assetFilePath() { + ghoul::filesystem::File dir(_assetDirectory); + return _assetDirectory + ghoul::filesystem::FileSystem::PathSeparator + _assetName + "." + AssetFileSuffix; +} + +std::string Asset::assetName() { + return _assetName; +} + +std::string Asset::assetDirectory() { + return _assetDirectory; +} + +std::string Asset::id() { + return assetFilePath(); +} + +AssetLoader* Asset::loader() { + return _loader; +} + +bool Asset::hasDependency(Asset* asset) { + auto it = std::find(_dependencies.begin(), _dependencies.end(), dependency); + return it != _dependencies.end(); +} + +void Asset::addDependency(Asset* dependency) { + if (readyState == Initialized) { + // TODO: Throw: cannot add dep while asset is initialized. + return; + } + + // Do nothing if the dependency already exists. + auto it = std::find(_dependencies.begin(), _dependencies.end(), dependency); + if (it != _dependencies.end()) { + return; + } + + _dependencies.push_back(dependency); + dependency->_dependants.push_back(this); + + addPropertySubOwner(dependency); +} + +void Asset::removeDependency(Asset* dependency) { + _dependencies.erase( + std::remove(_dependencies.begin(), _dependencies.end(), dependency), + _dependencies.end() + ); + std::vector& dependants = dependency->_dependants; + dependants.erase( + std::remove(dependants.begin(), dependants.end(), this), + dependants.end() + ); + + if (!dependency->hasInitializedDependants()) { + dependency->deinitialize(); + } +} + +void Asset::removeDependency(const std::string& assetId) { + auto dep = std::find_if(_dependencies.begin(), _dependencies.end(), [&assetId](const Asset& d) { + return d.id() == assetId; + }); + if (dep != _dependencies.end()) { + removeDependency(dep); + } else { + LERROR("No such dependency '" << assetId << "'"); + } +} + +void Asset::dependantDidInitialize(Asset* dependant) { + loader()->callOnDependantInitialize(this, dependant); +} + +void Asset::dependantWillDeinitialize(Asset* dependant) { + loader()->callOnDependantDeinitialize(this, dependant); +} + +bool Asset::hasDependants() { + bool foundDep = false; + for (auto& dependant : _dependants) { + if (dependant->hasDependency(this)) { + foundDep = true; + } + } + return foundDep; +} + +bool Asset::hasInitializedDependants() { + bool foundInitializedDep = false; + for (auto& dependant : _dependants) { + if (dependant->isInitialized() && dependant->hasDependency(this)) { + foundInitializedDep = true; + } + } + return foundInitializedDep; +} + +// Dependency toggle +Asset::Optional::Optional(Asset* asset, Asset* owner, bool enabled) + : PropertyOwner({ dependency->name(), dependency->name() }) + , _enabled({ "enabled", "Enabled", "Enable optional" }, enabled) + , _asset(asset) + , _owner(owner) +{ + addProperty(_enabled); + addPropertySubOwner(asset); + _enabled.onChange([this]() { + _owner->setOptionalEnabled( + asset, + _enabled + ); + }); +} + +} \ No newline at end of file diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 8cc3e75db4..051a732824 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -24,6 +24,7 @@ #include +#include #include #include @@ -42,7 +43,8 @@ namespace { const char* SyncTableName = "sync"; const char* ImportFunctionName = "import"; - const char* ImportToggleFunctionName = "importToggle"; + const char* ImportOptionalFunctionName = "importOptional"; + const char* SyncedResourceFunctionName = "syncedResource"; const char* LocalResourceFunctionName = "localResource"; const char* OnInitializeFunctionName = "onInitialize"; @@ -52,24 +54,15 @@ namespace { const char* DependantsTableName = "_dependants"; const char* _loggerCat = "AssetLoader"; - - bool isRelative(std::string path) { - if (path.size() > 2) { - if (path[0] == '.' && path[1] == '/') return true; - } - if (path.size() > 3) { - if (path[0] == '.' && path[1] == '.' && path[2] == '/') return true; - } - return false; - }; } namespace openspace { namespace assetloader { -int importAsset(lua_State* state) { - AssetLoader *assetLoader = (AssetLoader*)lua_touserdata(state, lua_upvalueindex(1)); +int importDependency(lua_State* state) { + AssetLoader *assetLoader = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); int nArguments = lua_gettop(state); if (nArguments != 1) { @@ -79,38 +72,52 @@ int importAsset(lua_State* state) { std::string assetName = luaL_checkstring(state, 1); try { - return assetLoader->importAssetLua(assetName, false, false); + return assetLoader->importDependencyLua(assetName); } catch (const ghoul::RuntimeError& e) { - return luaL_error(state, "Failed to import asset '%s'. %s: %s", assetName.c_str(), e.message.c_str(), e.component.c_str()); + return luaL_error( + state, + "Failed to import asset '%s'. %s: %s", + assetName.c_str(), + e.message.c_str(), + e.component.c_str() + ); } } -int importAssetToggle(lua_State* state) { - AssetLoader *assetLoader = (AssetLoader*)lua_touserdata(state, lua_upvalueindex(1)); +int importOptional(lua_State* state) { + AssetLoader *assetLoader = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); int nArguments = lua_gettop(state); if (nArguments != 2) { return luaL_error(state, "Expected 2 arguments, got %i", nArguments); } - - bool toggleEnabled = lua_toboolean(state, 2); - + std::string assetName = luaL_checkstring(state, 1); + bool enabled = lua_toboolean(state, 2); + try { - return assetLoader->importAssetLua(assetName, true, toggleEnabled); + return assetLoader->importOptionalLua(assetName, enabled); } catch (const ghoul::RuntimeError& e) { - return luaL_error(state, "Failed to import asset '%s'. %s: %s", assetName.c_str(), e.message.c_str(), e.component.c_str()); + return luaL_error( + state, + "Failed to import optional asset '%s'. %s: %s", + assetName.c_str(), + e.message.c_str(), + e.component.c_str()); } } int resolveLocalResource(lua_State* state) { - AssetLoader::Asset* asset = (AssetLoader::Asset*)lua_touserdata(state, lua_upvalueindex(1)); - return asset->resolveLocalResourceLua(); + Asset* asset = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); + return asset->loader()->resolveLocalResourceLua(asset); } int resolveSyncedResource(lua_State* state) { - AssetLoader::Asset* asset = (AssetLoader::Asset*)lua_touserdata(state, lua_upvalueindex(1)); - return asset->resolveSyncedResourceLua(); + Asset* asset = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); + return asset->loader()->resolveSyncedResourceLua(asset); } int noOperation(lua_State* state) { @@ -119,10 +126,16 @@ int noOperation(lua_State* state) { } // namespace assetloader -AssetLoader::AssetLoader(ghoul::lua::LuaState* luaState, std::string assetRoot, std::string syncRoot) - : _luaState(luaState) +AssetLoader::AssetLoader( + ghoul::lua::LuaState& luaState, + ResourceSynchronizer& resourceSynchronizer, + std::string assetRoot, + std::string syncRootDirectory +) + : _luaState(&luaState) , _rootAsset(std::make_unique(this, std::move(assetRoot))) - , _syncRoot(std::move(syncRoot)) + , _syncRootDirectory(std::move(syncRootDirectory)) + , _resourceSynchronizer(&resourceSynchronizer) { pushAsset(_rootAsset.get()); @@ -131,50 +144,24 @@ AssetLoader::AssetLoader(ghoul::lua::LuaState* luaState, std::string assetRoot, lua_setglobal(*_luaState, AssetsTableName); } -AssetLoader::Asset* AssetLoader::importAsset( - const std::string& name, - bool togglableInitializationRequirement, - bool toggleOn) -{ +Asset* AssetLoader::loadAsset(std::string name) { ghoul::filesystem::Directory directory = currentDirectory(); - std::unique_ptr newAsset = std::make_unique(this, directory, name); - const std::string id = newAsset->id(); + std::unique_ptr asset = std::make_unique(this, directory, name); - Asset* asset = newAsset.get(); - - // Check if asset is already loaded. - const auto it = _importedAssets.find(id); - const bool loaded = it != _importedAssets.end(); - if (loaded) { - asset = it->second.get(); - } - - InitializationRequirement reqInit = InitializationRequirement::Yes; - if (togglableInitializationRequirement && !toggleOn) { - reqInit = InitializationRequirement::No; - } - - Asset* dependant = _assetStack.back(); - dependant->addDependency(asset, togglableInitializationRequirement, reqInit); - - if (loaded) { - return asset; - } + pushAsset(asset); + ghoul::OnScopeExit e([this]() { + popAsset(); + }); const std::string path = asset->assetFilePath(); if (!FileSys.fileExists(path)) { throw ghoul::FileNotFoundError(path); } - // Actually loading asset. - pushAsset(asset); - ghoul::OnScopeExit e([this]() { - popAsset(); - }); - try { ghoul::lua::runScriptFile(*_luaState, path); - } catch (const ghoul::lua::LuaRuntimeException& e) { + } + catch (const ghoul::lua::LuaRuntimeException& e) { LERROR(e.message); return nullptr; } @@ -183,19 +170,43 @@ AssetLoader::Asset* AssetLoader::importAsset( return nullptr; } - LDEBUG("Imported asset " << asset->id()); - - _importedAssets.emplace(id, std::move(newAsset)); + Asset* rawAsset = asset.get(); + _importedAssets.emplace(id, std::move(asset)); - return _importedAssets[id].get(); + return rawAsset; +} + +Asset* AssetLoader::getAsset(std::string name) { + ghoul::filesystem::Directory directory = currentDirectory(); + std::string assetId = generateAssetId(directory, name); + + // Check if asset is already loaded. + const auto it = _importedAssets.find(assetId); + const bool loaded = it != _importedAssets.end(); + + return loaded ? it->second.get() : loadAsset(name); +} + +AssetLoader::Asset* AssetLoader::importDependency(const std::string& name) { + Asset* asset = getAsset(name); + Asset* dependant = _assetStack.back(); + dependant->addDependency(asset); + return asset; +} + +AssetLoader::Asset* AssetLoader::importOptional(const std::string& name, bool enabled) { + Asset* asset = getAsset(name); + Asset* owner = _assetStack.back(); + owner->addOptional(asset, enabled); + return asset; } ghoul::filesystem::Directory AssetLoader::currentDirectory() { return _assetStack.back()->assetDirectory(); } -void AssetLoader::loadAsset(const std::string & identifier) { - ghoul_assert(_assetStack.size() == 1, "Can only load an asset from the root asset"); +void AssetLoader::importAsset(const std::string & identifier) { + ghoul_assert(_assetStack.size() == 1, "Can only import an asset from the root asset"); try { importAsset(identifier); } @@ -205,8 +216,8 @@ void AssetLoader::loadAsset(const std::string & identifier) { } -void AssetLoader::unloadAsset(const std::string & identifier) { - ghoul_assert(_assetStack.size() == 1, "Can only unload an asset from the root asset"); +void AssetLoader::unimportAsset(const std::string & identifier) { + ghoul_assert(_assetStack.size() == 1, "Can only unimport an asset from the root asset"); ghoul::filesystem::Directory directory = currentDirectory(); Asset tempAsset(this, directory, identifier); @@ -225,8 +236,92 @@ AssetLoader::Asset* AssetLoader::rootAsset() { return _rootAsset.get(); } -const std::string& AssetLoader::syncRoot() { - return _syncRoot; +const std::string& AssetLoader::syncRootDirectory() { + return _syncRootDirectory; +} + +void AssetLoader::callOnInitialize(Asset * asset) { + if (asset == _rootAsset.get()) { + return; + } + lua_getglobal(*_luaState, AssetsTableName); + lua_getfield(*_luaState, -1, asset->id().c_str()); + lua_getfield(*_luaState, -1, OnInitializeFunctionName); + const int status = lua_pcall(*_luaState, 0, 0, 0); + if (status != LUA_OK) { + throw ghoul::lua::LuaExecutionException(lua_tostring(*state, -1)); + } +} + +void AssetLoader::callOnDeinitialize(Asset* asset) { + if (asset == _rootAsset.get()) { + return; + } + lua_getglobal(*_luaState, AssetsTableName); + lua_getfield(*_luaState, -1, asset->id().c_str()); + lua_getfield(*_luaState, -1, OnDeinitializeFunctionName); + const int status = lua_pcall(*_luaState, 0, 0, 0); + if (status != LUA_OK) { + throw ghoul::lua::LuaExecutionException(lua_tostring(*state, -1)); + } +} + +void AssetLoader::callOnDependantInitialize(Asset* asset, Asset* dependant) { + if (asset == _rootAsset.get()) { + return; + } + lua_getglobal(*_luaState, AssetsTableName); + lua_getfield(*_luaState, -1, asset->id().c_str()); + lua_getfield(*_luaState, -1, DependantsTableName); + lua_getfield(*_luaState, -1, dependant->id().c_str()); + lua_getfield(*_luaState, -1, OnInitializeFunctionName); + const int status = lua_pcall(*_luaState, 0, 0, 0); + if (status != LUA_OK) { + throw ghoul::lua::LuaLoadingException(lua_tostring(*state, -1)); + } +} + +void AssetLoader::callOnDependantDeinitialize(Asset* asset, Asset* dependant) { + if (asset == _rootAsset.get()) { + return; + } + + lua_getglobal(*_luaState, AssetsTableName); + lua_getfield(*_luaState, -1, asset->id().c_str()); + lua_getfield(*_luaState, -1, DependantsTableName); + lua_getfield(*_luaState, -1, dependant->id().c_str()); + lua_getfield(*_luaState, -1, OnDeinitializeFunctionName); + const int status = lua_pcall(*_luaState, 0, 0, 0); + if (status != LUA_OK) { + throw ghoul::lua::LuaLoadingException(lua_tostring(*state, -1)); + } +} + + +int AssetLoader::resolveLocalResourceLua(Asset* asset) { + int nArguments = lua_gettop(*state); + if (nArguments != 1) { + return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments); + } + + std::string resourceName = luaL_checkstring(*_luaState, -1); + std::string resolved = asset->resolveLocalResource(resourceName); + + lua_pushstring(*state, resolved.c_str()); + return 1; +} + +int AssetLoader::resolveSyncedResourceLua(Asset* asset) { + int nArguments = lua_gettop(*state); + if (nArguments != 1) { + return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments); + } + + std::string resourceName = luaL_checkstring(*_luaState, -1); + std::string resolved = asset->resolveSyncedResource(resourceName); + + lua_pushstring(*state, resolved.c_str()); + return 1; } void AssetLoader::pushAsset(Asset* asset) { @@ -254,14 +349,14 @@ void AssetLoader::pushAsset(Asset* asset) { lua_pushcclosure(*_luaState, &assetloader::resolveSyncedResource, 1); lua_setfield(*_luaState, assetTableIndex, SyncedResourceFunctionName); - // Register import function - lua_pushlightuserdata(*_luaState, asset->loader()); - lua_pushcclosure(*_luaState, &assetloader::importAsset, 1); + // Register import-dependency function + lua_pushlightuserdata(*_luaState, this); + lua_pushcclosure(*_luaState, &assetloader::importDependency, 1); lua_setfield(*_luaState, assetTableIndex, ImportFunctionName); - // Register importToggle function - lua_pushlightuserdata(*_luaState, asset->loader()); - lua_pushcclosure(*_luaState, &assetloader::importAssetToggle, 1); + // Register import-optional function + lua_pushlightuserdata(*_luaState, this); + lua_pushcclosure(*_luaState, &assetloader::importOptional, 1); lua_setfield(*_luaState, assetTableIndex, ImportToggleFunctionName); // Register default onDeinitialize function @@ -301,13 +396,29 @@ void AssetLoader::updateLuaGlobals() { lua_setglobal(*_luaState, AssetGlobalVariableName); } -int AssetLoader::importAssetLua(std::string assetName, bool togglableInitializationRequirement, bool toggleEnabled) { +int AssetLoader::importDependencyLua(std::string assetName) { Asset* importer = _assetStack.back(); - Asset* importedAsset = importAsset(assetName, togglableInitializationRequirement, toggleEnabled); + Asset* importedAsset = importDependency(assetName, toggleEnabled); if (!importedAsset) { return luaL_error(*_luaState, "Asset '%s' not found", assetName.c_str()); } + return createLuaTableEntries(importer, importedAsset); +} + +int AssetLoader::importOptionalLua(std::string assetName, bool enabled) { + Asset* importer = _assetStack.back(); + + Asset* importedAsset = importOptional(assetName, enabled); + if (!importedAsset) { + return luaL_error(*_luaState, "Asset '%s' not found", assetName.c_str()); + } + return createLuaTableEntries(importer, importedAsset); +} + + + +void AssetLoader::createAssetLuaTableEntries(Asset* importer, Asset* importedAsset) { const std::string importerId = importer->id(); const std::string importedAssetId = importedAsset->id(); @@ -348,15 +459,15 @@ scripting::LuaLibrary AssetLoader::luaLibrary() { "", { { - "loadAsset", - &luascriptfunctions::loadAsset, + "importAsset", + &luascriptfunctions::importAsset, {this}, "string", "" }, { - "unloadAsset", - &luascriptfunctions::unloadAsset, + "unimportAsset", + &luascriptfunctions::unimportAsset, {this}, "string", "" @@ -365,351 +476,4 @@ scripting::LuaLibrary AssetLoader::luaLibrary() { }; } - - -// Asset methods. - -std::string AssetLoader::Asset::resolveLocalResource(std::string resourceName) { - std::string currentAssetDirectory = assetDirectory(); - return currentAssetDirectory + ghoul::filesystem::FileSystem::PathSeparator + resourceName; -} - -std::string AssetLoader::Asset::syncDirectory() { - std::string currentAssetDirectory = assetDirectory(); - std::string rootAssetDirectory = loader()->rootAsset()->assetDirectory(); - std::string relativePath = FileSys.relativePath(currentAssetDirectory, rootAssetDirectory); - - return loader()->syncRoot() + - ghoul::filesystem::FileSystem::PathSeparator + - relativePath + - ghoul::filesystem::FileSystem::PathSeparator + - assetName(); -} - -bool AssetLoader::Asset::isInitialized() { - return _initialized; -} - -bool AssetLoader::Asset::hasLuaTable() { - return _hasLuaTable; -} - -void AssetLoader::Asset::initialize() { - LDEBUG("Initializing asset " << id()); - if (_initialized) { - return; - } - - // Initialize dependencies - for (auto& dependency : _dependencies) { - dependency.first->initialize(); - } - - _initialized = true; - - // Call onInitialize - if (_hasLuaTable) { - ghoul::lua::LuaState* state = loader()->luaState(); - lua_getglobal(*state, AssetsTableName); - lua_getfield(*state, -1, id().c_str()); - lua_getfield(*state, -1, OnInitializeFunctionName); - const int status = lua_pcall(*state, 0, 0, 0); - if (status != LUA_OK) { - throw ghoul::lua::LuaExecutionException(lua_tostring(*state, -1)); - } - } - - // Notify dependencies - for (auto& dependency : _dependencies) { - dependency.first->dependantDidInitialize(this); - } -} - -void AssetLoader::Asset::deinitialize() { - if (!_initialized) { - return; - } - - // Notify dependencies - for (auto& dependency : _dependencies) { - dependency.first->dependantWillDeinitialize(this); - } - - // Call onDeinitialize - if (_hasLuaTable) { - ghoul::lua::LuaState* state = loader()->luaState(); - lua_getglobal(*state, AssetsTableName); - lua_getfield(*state, -1, id().c_str()); - lua_getfield(*state, -1, OnDeinitializeFunctionName); - const int status = lua_pcall(*state, 0, 0, 0); - if (status != LUA_OK) { - throw ghoul::lua::LuaExecutionException(lua_tostring(*state, -1)); - } - } - - _initialized = false; - - // Make sure no dependencies are left dangling - for (auto& dependency : _dependencies) { - if (!dependency.first->hasInitializedDependants(InitializationRequirement::Yes)) { - dependency.first->deinitialize(); - } - } -} - -std::string AssetLoader::Asset::resolveSyncedResource(std::string resourceName) { - return syncDirectory() + - ghoul::filesystem::FileSystem::PathSeparator + - resourceName; -} - -int AssetLoader::Asset::resolveLocalResourceLua() { - ghoul::lua::LuaState* state = loader()->luaState(); - int nArguments = lua_gettop(*state); - if (nArguments != 1) { - return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments); - } - - std::string resourceName = luaL_checkstring(*state, -1); - std::string resolved = resolveLocalResource(resourceName); - - lua_pushstring(*state, resolved.c_str()); - return 1; -} - -int AssetLoader::Asset::resolveSyncedResourceLua() { - ghoul::lua::LuaState* state = loader()->luaState(); - int nArguments = lua_gettop(*state); - if (nArguments != 1) { - return luaL_error(*state, "Expected %i arguments, got %i", 1, nArguments); - } - - std::string resourceName = luaL_checkstring(*state, -1); - std::string resolved = resolveSyncedResource(resourceName); - - lua_pushstring(*state, resolved.c_str()); - return 1; -} - -AssetLoader::Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory directory) - : PropertyOwner({ "RootAsset", "Root asset" }) - , _assetDirectory(directory) - , _loader(loader) - , _initialized(false) - , _hasLuaTable(false) -{} - -AssetLoader::Asset::Asset(AssetLoader* loader, ghoul::filesystem::Directory baseDirectory, std::string assetPath) - : PropertyOwner({ assetPath, assetPath }) - , _initialized(false) - , _hasLuaTable(true) - , _loader(loader) -{ - if (isRelative(assetPath)) { - ghoul::filesystem::File assetFile = - static_cast(baseDirectory) + - ghoul::filesystem::FileSystem::PathSeparator + - assetPath + - "." + - AssetFileSuffix; - - _assetDirectory = assetFile.directoryName(); - _assetName = assetFile.baseName(); - } else { - std::string assetRoot = ghoul::filesystem::Directory(loader->rootAsset()->assetDirectory()); - ghoul::filesystem::File assetFile = - assetRoot + - ghoul::filesystem::FileSystem::PathSeparator + - assetPath + - "." + - AssetFileSuffix; - - _assetDirectory = assetFile.directoryName(); - _assetName = assetFile.baseName(); - } -} - -std::string AssetLoader::Asset::assetFilePath() { - ghoul::filesystem::File dir(_assetDirectory); - return _assetDirectory + ghoul::filesystem::FileSystem::PathSeparator + _assetName + "." + AssetFileSuffix; -} - -std::string AssetLoader::Asset::assetName() { - return _assetName; -} - -std::string AssetLoader::Asset::assetDirectory() { - return _assetDirectory; -} - -std::string AssetLoader::Asset::id() { - return assetFilePath(); -} - -AssetLoader* AssetLoader::Asset::loader() { - return _loader; -} - -ghoul::Dictionary AssetLoader::Asset::syncDictionary() { - ghoul::lua::LuaState* state = loader()->luaState(); - - lua_getglobal(*state, AssetsTableName); - lua_getfield(*state, -1, id().c_str()); - lua_getfield(*state, -1, SyncTableName); - - ghoul::Dictionary dictionary; - ghoul::lua::luaDictionaryFromState(*state, dictionary); - - return dictionary; -} - -bool AssetLoader::Asset::hasDependency(Asset* asset, InitializationRequirement initReq) { - auto it = std::find_if(_dependencies.begin(), _dependencies.end(), [asset](const Dependency& d) { - return d.first == asset; - }); - if (it == _dependencies.end()) { - return false; - } - return initReq ? (it->second == true) : true; -} - -void AssetLoader::Asset::addDependency(Asset* dependency, bool togglableInitReq, InitializationRequirement initReq) { - // Do nothing if the dependency already exists. - auto it = std::find_if(_dependencies.begin(), _dependencies.end(), [dependency](const Dependency& d) { - return d.first == dependency; - }); - if (it != _dependencies.end()) { - return; - } - - if (_initialized && initReq) { - dependency->initialize(); - } - _dependencies.push_back(std::make_pair(dependency, initReq)); - dependency->_dependants.push_back(this); - - if (togglableInitReq) { - std::unique_ptr dt = std::make_unique(dependency, this, initReq); - addPropertySubOwner(dt.get()); - _dependencyToggles.push_back(std::move(dt)); - } else { - addPropertySubOwner(dependency); - } -} - -void AssetLoader::Asset::setInitializationRequirement(Asset* dependency, InitializationRequirement initReq) { - auto it = std::find_if(_dependencies.begin(), _dependencies.end(), [dependency](const Dependency& d) { - return d.first == dependency; - }); - if (it == _dependencies.end()) { - LERROR("The dependency does not exist"); - } - it->second = initReq; - - if (_initialized && initReq) { - dependency->initialize(); - dependency->dependantDidInitialize(this); - } - if (!initReq && !dependency->hasInitializedDependants(InitializationRequirement::Yes)) { - dependency->dependantWillDeinitialize(this); - dependency->deinitialize(); - } -} - -void AssetLoader::Asset::removeDependency(Asset * dependency) { - _dependencies.erase( - std::remove_if(_dependencies.begin(), _dependencies.end(), [dependency](const Dependency& d) { - return d.first == dependency; - }), - _dependencies.end() - ); - std::vector& dependants = dependency->_dependants; - dependants.erase( - std::remove(dependants.begin(), dependants.end(), this), - dependants.end() - ); - - if (!dependency->hasInitializedDependants(InitializationRequirement::No)) { - dependency->deinitialize(); - } -} - -void AssetLoader::Asset::removeDependency(const std::string& assetId) { - auto dep = std::find_if(_dependencies.begin(), _dependencies.end(), [&assetId](const Dependency& d) { - return d.first->id() == assetId; - }); - if (dep != _dependencies.end()) { - removeDependency(dep->first); - } else { - LERROR("No such dependency '" << assetId << "'"); - } -} - -void AssetLoader::Asset::dependantDidInitialize(Asset* dependant) { - if (dependant->_hasLuaTable) { - ghoul::lua::LuaState* state = _loader->luaState(); - lua_getglobal(*state, AssetsTableName); - lua_getfield(*state, -1, id().c_str()); - lua_getfield(*state, -1, DependantsTableName); - lua_getfield(*state, -1, dependant->id().c_str()); - lua_getfield(*state, -1, OnInitializeFunctionName); - const int status = lua_pcall(*state, 0, 0, 0); - if (status != LUA_OK) { - throw ghoul::lua::LuaLoadingException(lua_tostring(*state, -1)); - } - } -} - -void AssetLoader::Asset::dependantWillDeinitialize(Asset* dependant) { - if (dependant->_hasLuaTable) { - ghoul::lua::LuaState* state = _loader->luaState(); - lua_getglobal(*state, AssetsTableName); - lua_getfield(*state, -1, id().c_str()); - lua_getfield(*state, -1, DependantsTableName); - lua_getfield(*state, -1, dependant->id().c_str()); - lua_getfield(*state, -1, OnDeinitializeFunctionName); - const int status = lua_pcall(*state, 0, 0, 0); - if (status != LUA_OK) { - throw ghoul::lua::LuaLoadingException(lua_tostring(*state, -1)); - } - } -} - -bool AssetLoader::Asset::hasDependant(InitializationRequirement initReq) { - bool foundDep = false; - for (auto& dependant : _dependants) { - if (dependant->hasDependency(this, initReq)) { - foundDep = true; - } - } - return foundDep; -} - -bool AssetLoader::Asset::hasInitializedDependants(InitializationRequirement initReq) { - bool foundInitializedDep = false; - for (auto& dependant : _dependants) { - if (dependant->isInitialized() && dependant->hasDependency(this, initReq)) { - foundInitializedDep = true; - } - } - return foundInitializedDep; -} - -// Dependency toggle -AssetLoader::DependencyToggle::DependencyToggle(Asset* dependency, Asset* dependant, bool enabled) - : PropertyOwner({ dependency->name(), dependency->name() }) - , _enabled({ "enabled", "Enabled", "Enable dependency" }, enabled) - , _dependency(dependency) - , _dependant(dependant) -{ - addProperty(_enabled); - addPropertySubOwner(_dependency); - _enabled.onChange([this]() { - _dependant->setInitializationRequirement( - _dependency, - _enabled ? InitializationRequirement::Yes : InitializationRequirement::No - ); - }); -} - } diff --git a/src/scene/assetloader_lua.inl b/src/scene/assetloader_lua.inl index 6cfa042775..44037821ef 100644 --- a/src/scene/assetloader_lua.inl +++ b/src/scene/assetloader_lua.inl @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -26,29 +26,29 @@ namespace openspace { namespace luascriptfunctions { -int loadAsset(lua_State* state) { - AssetLoader *assetLoader = (AssetLoader*)lua_touserdata(state, lua_upvalueindex(1)); +int importAsset(lua_State* state) { + AssetLoader *assetLoader = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); int nArguments = lua_gettop(state); - SCRIPT_CHECK_ARGUMENTS("loadAsset", state, 1, nArguments); + SCRIPT_CHECK_ARGUMENTS("importAsset", state, 1, nArguments); std::string assetName = luaL_checkstring(state, -1); - assetLoader->loadAsset(assetName); + assetLoader->importAsset(assetName); return 0; } -int unloadAsset(lua_State* state) { - AssetLoader *assetLoader = (AssetLoader*)lua_touserdata(state, lua_upvalueindex(1)); +int unimportAsset(lua_State* state) { + AssetLoader *assetLoader = + reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); int nArguments = lua_gettop(state); - SCRIPT_CHECK_ARGUMENTS("unloadAsset", state, 1, nArguments); + SCRIPT_CHECK_ARGUMENTS("unimportAsset", state, 1, nArguments); std::string assetName = luaL_checkstring(state, -1); - assetLoader->unloadAsset(assetName); - return 0; - + assetLoader->unimportAsset(assetName); return 0; } diff --git a/src/scene/sceneloader.cpp b/src/scene/sceneloader.cpp index bb92445324..e19e04048d 100644 --- a/src/scene/sceneloader.cpp +++ b/src/scene/sceneloader.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -22,6 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include #include #include #include @@ -89,6 +90,14 @@ void SceneLoader::loadScene(Scene* scene, const std::string& path) { std::string assetName = assetDictionary.value(key); _assetLoader->loadAsset(assetName); } + + // Sync all resources from assets that are dependencies of root asset. + // whenever an asset has all its resources synced: init the asset. + //_assetLoader->rootAsset()->getSynchronizations(); + + // also show + + try { _assetLoader->rootAsset()->initialize(); } catch (const ghoul::RuntimeError& e) { diff --git a/modules/sync/syncs/resourcesynchronization.h b/src/util/resourcesynchronizer.cpp similarity index 87% rename from modules/sync/syncs/resourcesynchronization.h rename to src/util/resourcesynchronizer.cpp index 5d965b9cf4..2f71b5f065 100644 --- a/modules/sync/syncs/resourcesynchronization.h +++ b/src/util/resourcesynchronizer.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -22,13 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_SYNC___RESOURCESYNCHRONIZATION___H__ -#define __OPENSPACE_MODULE_SYNC___RESOURCESYNCHRONIZATION___H__ +#include namespace openspace { - } // namespace openspace - -#endif // __OPENSPACE_MODULE_SYNC___RESOURCESYNCHRONIZATION___H__