diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 64a94e1a57..be85feb5d8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -2,8 +2,8 @@ #include #include +#include #include -#include #include #include @@ -38,6 +38,7 @@ #include +#include #include #include @@ -742,8 +743,10 @@ void OMW::Engine::prepareEngine() mWorld = std::make_unique( mResourceSystem.get(), mActivationDistanceOverride, mCellName, mCfgMgr.getUserDataPath()); - std::thread loadDataThread( - [&] { mWorld->loadData(mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get()); }); + Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); + Loading::AsyncListener asyncListener(*listener); + auto dataLoading = std::async(std::launch::async, + [&] { mWorld->loadData(mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get(), &asyncListener); }); if (!mSkipMenu) { @@ -752,9 +755,12 @@ void OMW::Engine::prepareEngine() mWindowManager->playVideo(logo, true); } - Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); - loadDataThread.join(); + { + using namespace std::chrono_literals; + while (dataLoading.wait_for(50ms) != std::future_status::ready) + asyncListener.update(); + } listener->loadingOff(); mWorld->init(mViewer, rootNode, mWorkQueue.get(), *mUnrefQueue); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 960c831376..fd7afa2d8a 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -76,10 +76,6 @@ namespace MWGui void LoadingScreen::setLabel(const std::string& label, bool important) { - std::lock_guard guard(mMutex); - if (!isVisible()) - return; - mImportantLabel = important; mLoadingText->setCaptionWithReplacing(label); @@ -145,8 +141,6 @@ namespace MWGui void LoadingScreen::loadingOn(bool visible) { - std::lock_guard guard(mMutex); - // Early-out if already on if (mNestedLoadingCount++ > 0 && mMainWidget->getVisible()) return; @@ -187,8 +181,6 @@ namespace MWGui void LoadingScreen::loadingOff() { - std::lock_guard guard(mMutex); - if (--mNestedLoadingCount > 0) return; mLoadingBox->setVisible(true); // restore @@ -247,10 +239,6 @@ namespace MWGui void LoadingScreen::setProgress(size_t value) { - std::lock_guard guard(mMutex); - if (!isVisible()) - return; - // skip expensive update if there isn't enough visible progress if (mProgressBar->getWidth() <= 0 || value - mProgress < mProgressBar->getScrollRange() / mProgressBar->getWidth()) @@ -265,10 +253,6 @@ namespace MWGui void LoadingScreen::increaseProgress(size_t increase) { - std::lock_guard guard(mMutex); - if (!isVisible()) - return; - mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; value = std::min(value, mProgressBar->getScrollRange() - 1); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 939ee72191..2cd3f73576 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -2,7 +2,6 @@ #define MWGUI_LOADINGSCREEN_H #include -#include #include #include @@ -70,8 +69,6 @@ namespace MWGui bool mVisible; int mNestedLoadingCount; - std::mutex mMutex; - size_t mProgress; bool mShowWallpaper; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9852e32548..a09d5d4174 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -270,13 +270,12 @@ namespace MWWorld } void World::loadData(const Files::Collections& fileCollections, const std::vector& contentFiles, - const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder) + const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener) { mContentFiles = contentFiles; if (encoder) mReaders.setStatelessEncoder(encoder->getStatelessEncoder()); mESMVersions.resize(mContentFiles.size(), -1); - Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); loadContentFiles(fileCollections, contentFiles, encoder, listener); loadGroundcoverFiles(fileCollections, groundcoverFiles, encoder, listener); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dfdbe4d689..b45fecca43 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -199,7 +199,8 @@ namespace MWWorld const std::filesystem::path& userDataPath); void loadData(const Files::Collections& fileCollections, const std::vector& contentFiles, - const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder); + const std::vector& groundcoverFiles, ToUTF8::Utf8Encoder* encoder, + Loading::Listener* listener); // Must be called after `loadData`. void init(osgViewer::Viewer* viewer, osg::ref_ptr rootNode, SceneUtil::WorkQueue* workQueue, diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2f0025a2c7..519a6cef4a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -292,7 +292,7 @@ add_component_dir (terrain ) add_component_dir (loadinglistener - loadinglistener + loadinglistener asynclistener ) add_component_dir (myguiplatform diff --git a/components/loadinglistener/asynclistener.hpp b/components/loadinglistener/asynclistener.hpp new file mode 100644 index 0000000000..af121e3a2b --- /dev/null +++ b/components/loadinglistener/asynclistener.hpp @@ -0,0 +1,67 @@ +#ifndef COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H +#define COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H + +#include +#include +#include + +#include "loadinglistener.hpp" + +namespace Loading +{ + class AsyncListener : public Listener + { + public: + AsyncListener(Listener& baseListener) + : mBaseListener(baseListener) + { + } + + void setLabel(const std::string& label, bool important) override + { + std::lock_guard guard(mMutex); + mLabelUpdate = label; + mImportantLabel = important; + } + + void setProgressRange(size_t range) override + { + std::lock_guard guard(mMutex); + mRangeUpdate = range; + } + + void setProgress(size_t value) override + { + std::lock_guard guard(mMutex); + mProgressUpdate = value; + } + + void increaseProgress(size_t increase) override + { /* not implemented */ + } + + void update() + { + std::lock_guard guard(mMutex); + if (mLabelUpdate) + mBaseListener.setLabel(*mLabelUpdate, mImportantLabel); + if (mRangeUpdate) + mBaseListener.setProgressRange(*mRangeUpdate); + if (mProgressUpdate) + mBaseListener.setProgress(*mProgressUpdate); + mLabelUpdate = std::nullopt; + mRangeUpdate = std::nullopt; + mProgressUpdate = std::nullopt; + } + + private: + Listener& mBaseListener; + std::mutex mMutex; + std::optional mLabelUpdate; + bool mImportantLabel = false; + std::optional mRangeUpdate; + std::optional mProgressUpdate; + }; +} + +#endif // COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H