diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index ef086079..1a3243bc 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -44,7 +44,6 @@ function(sl_add_app) ${SL_PROJECT_ROOT}/apps/source/App.h ${SL_PROJECT_ROOT}/apps/source/CVCapture.h ${SL_PROJECT_ROOT}/apps/source/AppCommon.h - ${SL_PROJECT_ROOT}/apps/source/AppLoad.h ${SL_PROJECT_ROOT}/apps/source/SLScene.h ${SL_PROJECT_ROOT}/apps/source/SLInterface.h ${SL_PROJECT_ROOT}/apps/source/Scene.h @@ -54,7 +53,6 @@ function(sl_add_app) file(GLOB COMMON_SOURCES ${SL_PROJECT_ROOT}/apps/source/CVCapture.cpp ${SL_PROJECT_ROOT}/apps/source/AppCommon.cpp - ${SL_PROJECT_ROOT}/apps/source/AppLoad.cpp ${SL_PROJECT_ROOT}/apps/source/SLInterface.cpp ${SL_PROJECT_ROOT}/apps/source/SLProjectScene.cpp ${APP_SOURCES} diff --git a/apps/source/AppCommon.cpp b/apps/source/AppCommon.cpp index 1e2fa8f4..2c5fb453 100644 --- a/apps/source/AppCommon.cpp +++ b/apps/source/AppCommon.cpp @@ -11,9 +11,9 @@ * \remarks Please use clangformat to format the code. See more code style on * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style */ - -#include +#include #include +#include #include #include #include @@ -156,6 +156,128 @@ void AppCommon::registerCoreAssetsLoad() IOK_font); } //----------------------------------------------------------------------------- +/*! + * Deletes the current scene and creates a new one identified by the sceneID. + * All assets get registered for async loading while Imgui shows a progress + * spinner in the UI. After the parallel loading the scene gets assembled back + * in the main thread. + * \param sv Pointer to the sceneview + * \param sceneID Scene identifier defined in SLEnum + */ +void AppCommon::switchScene(SLSceneView* sv, SLSceneID sceneID) +{ + SLAssetManager*& am = AppCommon::assetManager; + SLAssetLoader*& al = AppCommon::assetLoader; + + SLfloat startLoadMS = GlobalTimer::timeMS(); + + ////////////////////// + // Delete old scene // + ////////////////////// + + if (App::config.onBeforeSceneDelete) + App::config.onBeforeSceneDelete(sv, AppCommon::scene); + + if (AppCommon::scene) + { + delete AppCommon::scene; + AppCommon::scene = nullptr; + } + + // Deactivate in general the device sensors + AppCommon::devRot.init(); + AppCommon::devLoc.init(); + + // reset existing sceneviews + for (auto* sceneView : AppCommon::sceneViews) + sceneView->unInit(); + + // Clear all data in the asset manager + am->clear(); + + //////////////////// + // Init new scene // + //////////////////// + + AppCommon::sceneID = sceneID; + SLScene* s = App::config.onNewScene(sceneID); + SL_LOG("Scene name : %s (SceneID: %d)", + s->name().c_str(), + AppCommon::sceneID); + + // Initialize all preloaded stuff from SLScene + s->init(am); + +#ifndef SL_EMSCRIPTEN + s->initOculus(AppCommon::dataPath + "shaders/"); +#endif + + // Reset the global SLGLState state + SLGLState::instance()->initAll(); + + /////////////////////////////// + // Prepare for async loading // + /////////////////////////////// + + // Register assets on the loader that have to be loaded before assembly. + al->scene(s); + s->registerAssetsToLoad(*al); + + // `onDone` is a wrapper around `onDoneLoading` that will be called + // in the main thread after loading. + auto onDone = std::bind(onDoneLoading, sv, s, startLoadMS); + + // Start loading assets asynchronously. + al->loadAssetsAsync(onDone); + + if (App::config.onBeforeSceneLoad) + App::config.onBeforeSceneLoad(sv, s); +} +//----------------------------------------------------------------------------- +void AppCommon::onDoneLoading(SLSceneView* sv, SLScene* s, SLfloat startLoadMS) +{ + SLAssetManager* am = AppCommon::assetManager; + SLAssetLoader* al = AppCommon::assetLoader; + + // Register a task to assemble the scene. + al->addLoadTask(std::bind(&SLScene::assemble, s, am, sv)); + + // `onDone` is a wrapper around `onDoneAssembling` that will be called + // in the main thread after loading. + auto onDone = std::bind(onDoneAssembling, sv, s, startLoadMS); + + // Start assembling the scene asynchronously. + al->loadAssetsAsync(onDone); + + if (App::config.onBeforeSceneAssembly) + App::config.onBeforeSceneAssembly(sv, s); +} +//----------------------------------------------------------------------------- +void AppCommon::onDoneAssembling(SLSceneView* sv, SLScene* s, SLfloat startLoadMS) +{ + /* Assign the scene to the sceneview. The sceneview exists and is used + * before it knows its scene. This is new since we do async loading and + * show a spinner in the sceneview. */ + sv->scene(s); + sv->postSceneLoad(); + + // Make sure the scene view has a camera + if (!sv->camera()) + sv->camera(sv->sceneViewCamera()); + + // call onInitialize on all scene views to init the scenegraph and stats + for (auto* sceneView : AppCommon::sceneViews) + if (sceneView != nullptr) + sceneView->onInitialize(); + + AppCommon::scene = s; + + if (App::config.onAfterSceneAssembly) + App::config.onAfterSceneAssembly(sv, s); + + s->loadTimeMS(GlobalTimer::timeMS() - startLoadMS); +} +//----------------------------------------------------------------------------- //! Calls the destructor of the single scene instance. /*! Destroys all data by calling the destructor of the single scene instance. All other date gets destroyed from there. This function gets called by the diff --git a/apps/source/AppCommon.h b/apps/source/AppCommon.h index a361da19..e6f6b348 100644 --- a/apps/source/AppCommon.h +++ b/apps/source/AppCommon.h @@ -12,8 +12,8 @@ * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style */ -#ifndef SLAPPLICATION_H -#define SLAPPLICATION_H +#ifndef SLAPPCOMMON_H +#define SLAPPCOMMON_H #include #include @@ -67,6 +67,7 @@ class AppCommon static void createApp(SLstring appName); static void registerCoreAssetsLoad(); + static void switchScene(SLSceneView* sv, SLSceneID sceneID); static void deleteApp(); static SLstring name; //!< Application name @@ -118,6 +119,9 @@ class AppCommon static const string PROFILE_FTP_DIR; //!< ftp directory for profiles upload private: + static void onDoneLoading(SLSceneView* sv, SLScene* s, SLfloat startLoadMS); + static void onDoneAssembling(SLSceneView* sv, SLScene* s, SLfloat startLoadMS); + static string _jobProgressMsg; //!< Text message to show during progress static atomic _jobProgressNum; //!< Integer value to show progress static atomic _jobProgressMax; //!< Max. integer progress value diff --git a/apps/source/AppLoad.cpp b/apps/source/AppLoad.cpp deleted file mode 100644 index dd8a8a86..00000000 --- a/apps/source/AppLoad.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** - * \file AppLoad.cpp - * \brief The AppLoad class is responsible for the async loading of scenes - * \date June 2024 - * \authors Marino von Wattenwyl - * \copyright http://opensource.org/licenses/GPL-3.0 - * \remarks Please use clangformat to format the code. See more code style on - * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -//----------------------------------------------------------------------------- -/*! - * Deletes the current scene and creates a new one identified by the sceneID. - * All assets get registered for async loading while Imgui shows a progress - * spinner in the UI. After the parallel loading the scene gets assembled back - * in the main thread. - * \param sv Pointer to the sceneview - * \param sceneID Scene identifier defined in SLEnum - */ -void AppLoad::switchScene(SLSceneView* sv, SLSceneID sceneID) -{ - SLAssetManager*& am = AppCommon::assetManager; - SLAssetLoader*& al = AppCommon::assetLoader; - - SLfloat startLoadMS = GlobalTimer::timeMS(); - - ////////////////////// - // Delete old scene // - ////////////////////// - - if (App::config.onBeforeSceneDelete) - App::config.onBeforeSceneDelete(sv, AppCommon::scene); - - if (AppCommon::scene) - { - delete AppCommon::scene; - AppCommon::scene = nullptr; - } - - // Deactivate in general the device sensors - AppCommon::devRot.init(); - AppCommon::devLoc.init(); - - // reset existing sceneviews - for (auto* sceneView : AppCommon::sceneViews) - sceneView->unInit(); - - // Clear all data in the asset manager - am->clear(); - - //////////////////// - // Init new scene // - //////////////////// - - AppCommon::sceneID = sceneID; - SLScene* s = App::config.onNewScene(sceneID); - SL_LOG("Scene name : %s (SceneID: %d)", - s->name().c_str(), - AppCommon::sceneID); - - // Initialize all preloaded stuff from SLScene - s->init(am); - -#ifndef SL_EMSCRIPTEN - s->initOculus(AppCommon::dataPath + "shaders/"); -#endif - - // Reset the global SLGLState state - SLGLState::instance()->initAll(); - - /////////////////////////////// - // Prepare for async loading // - /////////////////////////////// - - // Register assets on the loader that have to be loaded before assembly. - al->scene(s); - s->registerAssetsToLoad(*al); - - // `onDone` is a wrapper around `onDoneLoading` that will be called - // in the main thread after loading. - auto onDone = std::bind(onDoneLoading, sv, s, startLoadMS); - - // Start loading assets asynchronously. - al->loadAssetsAsync(onDone); - - if (App::config.onBeforeSceneLoad) - App::config.onBeforeSceneLoad(sv, s); -} -//----------------------------------------------------------------------------- -void AppLoad::onDoneLoading(SLSceneView* sv, SLScene* s, SLfloat startLoadMS) -{ - SLAssetManager* am = AppCommon::assetManager; - SLAssetLoader* al = AppCommon::assetLoader; - - // Register a task to assemble the scene. - al->addLoadTask(std::bind(&SLScene::assemble, s, am, sv)); - - // `onDone` is a wrapper around `onDoneAssembling` that will be called - // in the main thread after loading. - auto onDone = std::bind(onDoneAssembling, sv, s, startLoadMS); - - // Start assembling the scene asynchronously. - al->loadAssetsAsync(onDone); - - if (App::config.onBeforeSceneAssembly) - App::config.onBeforeSceneAssembly(sv, s); -} -//----------------------------------------------------------------------------- -void AppLoad::onDoneAssembling(SLSceneView* sv, SLScene* s, SLfloat startLoadMS) -{ - /* Assign the scene to the sceneview. The sceneview exists and is used - * before it knows its scene. This is new since we do async loading and - * show a spinner in the sceneview. */ - sv->scene(s); - sv->postSceneLoad(); - - // Make sure the scene view has a camera - if (!sv->camera()) - sv->camera(sv->sceneViewCamera()); - - // call onInitialize on all scene views to init the scenegraph and stats - for (auto* sceneView : AppCommon::sceneViews) - if (sceneView != nullptr) - sceneView->onInitialize(); - - AppCommon::scene = s; - - if (App::config.onAfterSceneAssembly) - App::config.onAfterSceneAssembly(sv, s); - - s->loadTimeMS(GlobalTimer::timeMS() - startLoadMS); -} -//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/apps/source/AppLoad.h b/apps/source/AppLoad.h deleted file mode 100644 index 58cffb92..00000000 --- a/apps/source/AppLoad.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * \file AppLoad.h - * \brief The AppLoad class is responsible for the async loading of scenes - * \date June 2024 - * \authors Marino von Wattenwyl - * \copyright http://opensource.org/licenses/GPL-3.0 - * \remarks Please use clangformat to format the code. See more code style on - * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style -*/ - -#ifndef APPLOAD_H -#define APPLOAD_H - -#include -#include - -//---------------------------------------------------------------------------- -//! The AppLoad class is responsible for the async loading of scenes -class AppLoad -{ -public: - static void switchScene(SLSceneView* sv, SLSceneID sceneID); - -private: - static void onDoneLoading(SLSceneView* sv, SLScene* s, SLfloat startLoadMS); - static void onDoneAssembling(SLSceneView* sv, SLScene* s, SLfloat startLoadMS); -}; -//----------------------------------------------------------------------------- - -#endif \ No newline at end of file diff --git a/apps/source/AsyncWorker.h b/apps/source/AsyncWorker.h deleted file mode 100644 index e78884a9..00000000 --- a/apps/source/AsyncWorker.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef ASYNC_WORKER_H -#define ASYNC_WORKER_H - -#include -#include - -class AsyncWorker -{ -public: - virtual ~AsyncWorker(); - - void start(); - void stop(); - //! if returns true, results are valid to be retrieved - bool isReady(); - -protected: - bool stopRequested(); - // call set ready when custom run finished - void setReady(); - - virtual void run(); - -private: - std::thread _thread; - - std::atomic_bool _stop{false}; - std::atomic_bool _ready{false}; -}; - -#endif diff --git a/apps/source/SLInterface.cpp b/apps/source/SLInterface.cpp index fd533a47..4a5144fe 100644 --- a/apps/source/SLInterface.cpp +++ b/apps/source/SLInterface.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -200,7 +199,7 @@ void slLoadCoreAssetsAsync() //----------------------------------------------------------------------------- void slSwitchScene(SLSceneView* sv, SLSceneID sceneID) { - AppLoad::switchScene(sv, sceneID); + AppCommon::switchScene(sv, sceneID); } //----------------------------------------------------------------------------- /*! Global sceneview construction function returning the index of the created diff --git a/apps/source/AsyncWorker.cpp b/modules/utils/source/AsyncWorker.cpp similarity index 51% rename from apps/source/AsyncWorker.cpp rename to modules/utils/source/AsyncWorker.cpp index 9fcd932b..060ab9cc 100644 --- a/apps/source/AsyncWorker.cpp +++ b/modules/utils/source/AsyncWorker.cpp @@ -1,17 +1,28 @@ -#include "AsyncWorker.h" +/** + * \file AsyncWorker.cpp + * \brief Implementation of an async worker thread + * \date May 2024 + * \authors Marino von Wattenwyl + * \copyright http://opensource.org/licenses/GPL-3.0 + * \remarks Please use clangformat to format the code. See more code style on + * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style +*/ + +#include #include +//----------------------------------------------------------------------------- AsyncWorker::~AsyncWorker() { stop(); } - +//----------------------------------------------------------------------------- void AsyncWorker::start() { _ready = false; _thread = std::thread(&AsyncWorker::run, this); } - +//----------------------------------------------------------------------------- void AsyncWorker::stop() { _stop = true; @@ -20,24 +31,24 @@ void AsyncWorker::stop() _stop = false; _ready = false; } - +//----------------------------------------------------------------------------- //! if returns true, results are valid to be retrieved bool AsyncWorker::isReady() { return _ready; } - +//----------------------------------------------------------------------------- bool AsyncWorker::stopRequested() { return _stop; } - +//----------------------------------------------------------------------------- // call set ready when custom run finished void AsyncWorker::setReady() { _ready = true; } - +//----------------------------------------------------------------------------- void AsyncWorker::run() { int n = 120; @@ -63,3 +74,4 @@ void AsyncWorker::run() Utils::log("AsyncWorker", "run ready"); setReady(); } +//----------------------------------------------------------------------------- diff --git a/modules/utils/source/AsyncWorker.h b/modules/utils/source/AsyncWorker.h new file mode 100644 index 00000000..5b3a3184 --- /dev/null +++ b/modules/utils/source/AsyncWorker.h @@ -0,0 +1,40 @@ +/** + * \file AsyncWorker.h + * \brief Declaration of an async worker thread class + * \date May 2024 + * \authors Marino von Wattenwyl + * \copyright http://opensource.org/licenses/GPL-3.0 + * \remarks Please use clangformat to format the code. See more code style on + * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style +*/ + +#ifndef ASYNC_WORKER_H +#define ASYNC_WORKER_H + +#include +#include + +//----------------------------------------------------------------------------- +//! AsyncWorker implements a async worker thread +class AsyncWorker +{ +public: + virtual ~AsyncWorker(); + + void start(); + void stop(); + bool isReady(); + +protected: + bool stopRequested(); + void setReady(); + virtual void run(); + +private: + std::thread _thread; + std::atomic_bool _stop{false}; + std::atomic_bool _ready{false}; +}; +//----------------------------------------------------------------------------- + +#endif diff --git a/apps/source/HttpDownloader.h b/modules/utils/source/HttpDownloader.h similarity index 100% rename from apps/source/HttpDownloader.h rename to modules/utils/source/HttpDownloader.h diff --git a/apps/source/LogWindow.cpp b/modules/utils/source/LogWindow.cpp similarity index 100% rename from apps/source/LogWindow.cpp rename to modules/utils/source/LogWindow.cpp diff --git a/apps/source/LogWindow.h b/modules/utils/source/LogWindow.h similarity index 100% rename from apps/source/LogWindow.h rename to modules/utils/source/LogWindow.h