From 2b339f6c0fd9242cd5bf800e68963acfa3abf479 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 11 Sep 2012 16:37:54 +0200 Subject: [PATCH] loading screen --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 13 ++- apps/openmw/mwbase/inputmanager.hpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwgui/loadingscreen.cpp | 108 +++++++++++++++++++++++ apps/openmw/mwgui/loadingscreen.hpp | 44 +++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 11 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwinput/inputmanagerimp.cpp | 5 +- apps/openmw/mwinput/inputmanagerimp.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 68 ++++++++++++++ files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_layers.xml | 1 + files/mygui/openmw_loading_screen.layout | 16 ++++ libs/openengine/gui/manager.cpp | 50 ++++++----- libs/openengine/gui/manager.hpp | 35 +++++--- 16 files changed, 314 insertions(+), 50 deletions(-) create mode 100644 apps/openmw/mwgui/loadingscreen.cpp create mode 100644 apps/openmw/mwgui/loadingscreen.hpp create mode 100644 files/mygui/openmw_loading_screen.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4cf3bd7fd..cffbc60c7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -29,7 +29,7 @@ add_openmw_dir (mwgui map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu - itemselection spellbuyingwindow + itemselection spellbuyingwindow loadingscreen ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 171fcde7c..82bd3b69b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,7 +67,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input - MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame); + MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false); // sound if (mUseSound) @@ -351,6 +351,11 @@ void OMW::Engine::go() mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions)); + // Sets up the input system + mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, + MWBase::Environment::get().getWorld()->getPlayer(), + *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); + // load cell ESM::Position pos; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; @@ -370,12 +375,6 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); } - // Sets up the input system - - mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, - MWBase::Environment::get().getWorld()->getPlayer(), - *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); - std::cout << "\nPress Q/ESC or close window to exit.\n"; mOgre->getRoot()->addFrameListener (this); diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 424501229..8293cbfa7 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -22,7 +22,7 @@ namespace MWBase virtual ~InputManager() {} - virtual void update(float dt) = 0; + virtual void update(float dt, bool loading) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 14b1051e8..bd8b7eb18 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -216,6 +216,8 @@ namespace MWBase virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; virtual void executeInConsole (const std::string& path) = 0; + + virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total) = 0; }; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp new file mode 100644 index 000000000..efda76caa --- /dev/null +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -0,0 +1,108 @@ +#include "loadingscreen.hpp" + +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" + +namespace MWGui +{ + + LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager) + : mSceneMgr(sceneMgr) + , mWindow(rw) + , WindowBase("openmw_loading_screen.layout", parWindowManager) + , mLoadingOn(false) + , mLastRenderTime(0.f) + { + getWidget(mLoadingText, "LoadingText"); + } + + LoadingScreen::~LoadingScreen() + { + } + + void LoadingScreen::setLoadingProgress (const std::string& stage, int depth, int current, int total) + { + if (!mLoadingOn) + loadingOn(); + + if (depth == 0) + { + mCurrentCellLoading = current; + mTotalCellsLoading = total; + + mCurrentRefLoading = 0; + + } + if (depth == 1) + { + mCurrentRefLoading = current; + mTotalRefsLoading = total; + } + + if (mTotalCellsLoading == 0) + { + loadingOff(); + return; + } + + float refProgress; + if (mTotalRefsLoading <= 1) + refProgress = 0; + else + refProgress = float(mCurrentRefLoading) / float(mTotalRefsLoading-1); + + float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); + assert(progress <= 1 && progress >= 0); + if (progress >= 1) + { + loadingOff(); + return; + } + + mLoadingText->setCaption(stage + "... " + Ogre::StringConverter::toString(progress)); + + static float loadingScreenFps = 40.f; + + //if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) + { + mLastRenderTime = mTimer.getMilliseconds (); + + + // Turn off rendering except the GUI + mSceneMgr->clearSpecialCaseRenderQueues(); + // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. + for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) + { + if (i > 10 && i < 90) + mSceneMgr->addSpecialCaseRenderQueue(i); + } + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + + // always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before + // (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow) + MWBase::Environment::get().getInputManager()->update(0, true); + + mWindow->update(); + + // resume 3d rendering + mSceneMgr->clearSpecialCaseRenderQueues(); + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + } + } + + void LoadingScreen::loadingOn() + { + setVisible(true); + mLoadingOn = true; + } + + + void LoadingScreen::loadingOff() + { + setVisible(false); + mLoadingOn = false; + } +} diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp new file mode 100644 index 000000000..199bde372 --- /dev/null +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -0,0 +1,44 @@ +#ifndef MWGUI_LOADINGSCREEN_H +#define MWGUI_LOADINGSCREEN_H + +#include +#include + +#include "window_base.hpp" + +namespace MWGui +{ + + class LoadingScreen : public WindowBase + { + public: + LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager); + virtual ~LoadingScreen(); + + void setLoadingProgress (const std::string& stage, int depth, int current, int total); + + private: + Ogre::SceneManager* mSceneMgr; + Ogre::RenderWindow* mWindow; + + unsigned long mLastRenderTime; + Ogre::Timer mTimer; + + MyGUI::TextBox* mLoadingText; + + int mCurrentCellLoading; + int mTotalCellsLoading; + int mCurrentRefLoading; + int mTotalRefsLoading; + + + bool mLoadingOn; + + void loadingOn(); + void loadingOff(); + }; + +} + + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 02718f365..196e898b0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -43,6 +43,7 @@ #include "alchemywindow.hpp" #include "spellwindow.hpp" #include "quickkeysmenu.hpp" +#include "loadingscreen.hpp" using namespace MWGui; @@ -67,6 +68,7 @@ WindowManager::WindowManager( , mConfirmationDialog(NULL) , mAlchemyWindow(NULL) , mSpellWindow(NULL) + , mLoadingScreen(NULL) , mCharGen(NULL) , mPlayerClass() , mPlayerName() @@ -146,6 +148,9 @@ WindowManager::WindowManager( mSpellWindow = new SpellWindow(*this); mQuickKeysMenu = new QuickKeysMenu(*this); + mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); + mLoadingScreen->setCoord (0,0,w,h); + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); // The HUD is always on @@ -679,6 +684,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector mBookWindow->center(); mQuickKeysMenu->center(); mSpellBuyingWindow->center(); + mLoadingScreen->setCoord (0,0,x,y); mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mInputBlocker->setSize(MyGUI::IntSize(x,y)); } @@ -897,3 +903,8 @@ void WindowManager::toggleHud () mHudEnabled = !mHudEnabled; mHud->setVisible (mHudEnabled); } + +void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) +{ + mLoadingScreen->setLoadingProgress (stage, depth, current, total); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a91478bbc..5327bb868 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -61,6 +61,7 @@ namespace MWGui class SettingsWindow; class AlchemyWindow; class QuickKeysMenu; + class LoadingScreen; class WindowManager : public MWBase::WindowManager { @@ -195,6 +196,8 @@ namespace MWGui virtual void executeInConsole (const std::string& path); + virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total); + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -219,6 +222,7 @@ namespace MWGui AlchemyWindow* mAlchemyWindow; SpellWindow* mSpellWindow; QuickKeysMenu* mQuickKeysMenu; + LoadingScreen* mLoadingScreen; CharacterCreation* mCharGen; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 022d7df3c..b198785d2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -233,14 +233,15 @@ namespace MWInput } } - void InputManager::update(float dt) + void InputManager::update(float dt, bool loading) { // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); // update values of channels (as a result of pressed keys) - mInputCtrl->update(dt); + if (!loading) + mInputCtrl->update(dt); // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9963c73c2..7d03f1d5b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -66,7 +66,7 @@ namespace MWInput virtual ~InputManager(); - virtual void update(float dt); + virtual void update(float dt, bool loading); virtual void changeInputMode(bool guiMode); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index eb03e9a7b..bcf4a2002 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -25,9 +25,14 @@ namespace const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); + int numRefs = cellRefList.list.size(); + int current = 0; for (typename T::List::iterator it = cellRefList.list.begin(); it != cellRefList.list.end(); it++) { + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); + ++current; + if (it->mData.getCount() || it->mData.isEnabled()) { MWWorld::Ptr ptr (&*it, &cell); @@ -175,6 +180,26 @@ namespace MWWorld CellStoreCollection::iterator active = mActiveCells.begin(); + // get the number of cells to unload + int numUnload = 0; + while (active!=mActiveCells.end()) + { + if (!((*active)->cell->data.flags & ESM::Cell::Interior)) + { + if (std::abs (X-(*active)->cell->data.gridX)<=1 && + std::abs (Y-(*active)->cell->data.gridY)<=1) + { + // keep cells within the new 3x3 grid + ++active; + continue; + } + } + ++active; + ++numUnload; + } + + int current = 0; + active = mActiveCells.begin(); while (active!=mActiveCells.end()) { if (!((*active)->cell->data.flags & ESM::Cell::Interior)) @@ -188,10 +213,35 @@ namespace MWWorld } } + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); + ++current; } + int numLoad = 0; + // get the number of cells to load + for (int x=X-1; x<=X+1; ++x) + for (int y=Y-1; y<=Y+1; ++y) + { + CellStoreCollection::iterator iter = mActiveCells.begin(); + + while (iter!=mActiveCells.end()) + { + assert (!((*iter)->cell->data.flags & ESM::Cell::Interior)); + + if (x==(*iter)->cell->data.gridX && + y==(*iter)->cell->data.gridY) + break; + + ++iter; + } + + if (iter==mActiveCells.end()) + ++numLoad; + } + // Load cells + current = 0; for (int x=X-1; x<=X+1; ++x) for (int y=Y-1; y<=Y+1; ++y) { @@ -212,7 +262,9 @@ namespace MWWorld { CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, current, numLoad); loadCell (cell); + ++current; } } @@ -275,14 +327,30 @@ namespace MWWorld // remove active CellStoreCollection::iterator active = mActiveCells.begin(); + // count number of cells to unload + int numUnload = 0; while (active!=mActiveCells.end()) { + ++active; + ++numUnload; + } + + // unload + int current = 0; + active = mActiveCells.begin(); + while (active!=mActiveCells.end()) + { + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + unloadCell (active++); + ++current; } // Load cell. std::cout << "cellName:" << cellName << std::endl; + + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); loadCell (cell); // adjust player diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 82fb64c76..fdf447e69 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -71,6 +71,7 @@ set(MYGUI_FILES openmw_itemselection_dialog.layout openmw_magicselection_dialog.layout openmw_spell_buying_window.layout + openmw_loading_screen.layout smallbars.png VeraMono.ttf markers.png diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 7a8d586d2..33a3ca40c 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -8,5 +8,6 @@ + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout new file mode 100644 index 000000000..1b99c91bd --- /dev/null +++ b/files/mygui/openmw_loading_screen.layout @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 58929ba8b..acb4ed9df 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -8,41 +8,43 @@ using namespace OEngine::GUI; void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { - assert(wnd); - assert(mgr); + assert(wnd); + assert(mgr); - using namespace MyGUI; + mSceneMgr = mgr; - // Enable/disable MyGUI logging to stdout. (Logging to MyGUI.log is - // still enabled.) In order to do this we have to initialize the log - // manager before the main gui system itself, otherwise the main - // object will get the chance to spit out a few messages before we - // can able to disable it. + using namespace MyGUI; - std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); - if(!logDir.empty()) - theLogFile.insert(0, logDir); + // Enable/disable MyGUI logging to stdout. (Logging to MyGUI.log is + // still enabled.) In order to do this we have to initialize the log + // manager before the main gui system itself, otherwise the main + // object will get the chance to spit out a few messages before we + // can able to disable it. - // Set up OGRE platform. We might make this more generic later. - mPlatform = new OgrePlatform(); - LogManager::getInstance().setSTDOutputEnabled(logging); - mPlatform->initialise(wnd, mgr, "General", theLogFile); + std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); + if(!logDir.empty()) + theLogFile.insert(0, logDir); + + // Set up OGRE platform. We might make this more generic later. + mPlatform = new OgrePlatform(); + LogManager::getInstance().setSTDOutputEnabled(logging); + mPlatform->initialise(wnd, mgr, "General", theLogFile); - // Create GUI - mGui = new Gui(); - mGui->initialise("core.xml"); + // Create GUI + mGui = new Gui(); + mGui->initialise("core.xml"); } void MyGUIManager::shutdown() { mGui->shutdown (); - delete mGui; - if(mPlatform) + delete mGui; + if(mPlatform) { - mPlatform->shutdown(); - delete mPlatform; + mPlatform->shutdown(); + delete mPlatform; } - mGui = NULL; - mPlatform = NULL; + mGui = NULL; + mPlatform = NULL; } diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index 781685acf..1ec2e2fcf 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -16,21 +16,28 @@ namespace Ogre namespace OEngine { namespace GUI { - class MyGUIManager - { - MyGUI::OgrePlatform *mPlatform; - MyGUI::Gui *mGui; + class MyGUIManager + { + MyGUI::OgrePlatform *mPlatform; + MyGUI::Gui *mGui; + Ogre::SceneManager* mSceneMgr; - public: - MyGUIManager() : mPlatform(NULL), mGui(NULL) {} - MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) - { setup(wnd,mgr,logging, logDir); } - ~MyGUIManager() { shutdown(); } + public: + MyGUIManager() : mPlatform(NULL), mGui(NULL) {} + MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) + { + setup(wnd,mgr,logging, logDir); + } + ~MyGUIManager() + { + shutdown(); + } - void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); - void shutdown(); + void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); + void shutdown(); - MyGUI::Gui *getGui() { return mGui; } - }; -}} + MyGUI::Gui *getGui() { return mGui; } + }; +} +} #endif