diff --git a/CMakeLists.txt b/CMakeLists.txt index fb3827588..392fdfc66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ set(OENGINE_OGRE set(OENGINE_GUI ${LIBDIR}/openengine/gui/manager.cpp + ${LIBDIR}/openengine/gui/layout.hpp ) set(OENGINE_BULLET diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 20011b0d9..511435108 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwgui merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers savegamedialog - recharge + recharge mode videowidget ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 47e0d016f..508b195e9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -339,6 +339,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) std::string aa = settings.getString("antialiasing", "Video"); windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, + settings.getBool("minimize on focus loss", "Video") ? "1" : "0"); + mOgre->createWindow("OpenMW", windowSettings); Bsa::registerResources (mFileCollections, mArchives, true, mFSStrict); @@ -356,6 +359,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding); mEnvironment.setWindowManager (window); + // Create sound system + mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); + + if (!mSkipMenu) + { + std::string logo = mFallbackMap["Movies_Company_Logo"]; + if (!logo.empty()) + window->playVideo(logo, 1); + } + // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, @@ -373,9 +386,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) Compiler::registerExtensions (mExtensions); - // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); - // Create script system mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); @@ -434,7 +444,19 @@ void OMW::Engine::go() // start in main menu if (!mSkipMenu) + { MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + try + { + // Is there an ini setting for this filename or something? + MWBase::Environment::get().getSoundManager()->streamMusic("Special/morrowind title.mp3"); + + std::string logo = mFallbackMap["Movies_Morrowind_Logo"]; + if (!logo.empty()) + MWBase::Environment::get().getWindowManager()->playVideo(logo, true); + } + catch (...) {} + } else MWBase::Environment::get().getStateManager()->newGame (true); diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 42922a5b3..d44da4974 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -25,7 +25,7 @@ namespace MWBase virtual ~InputManager() {} - virtual void update(float dt, bool loading) = 0; + virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0; virtual void changeInputMode(bool guiMode) = 0; diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 22dda0ce0..e4c480a8c 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -156,7 +156,7 @@ namespace MWBase /// paused we may want to do it manually (after equipping permanent enchantment) virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; - virtual void toggleAI() = 0; + virtual bool toggleAI() = 0; virtual bool isAIActive() = 0; virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector& objects) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4fce19e33..e3bd428e2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -96,6 +96,10 @@ namespace MWBase */ virtual void update() = 0; + /// @note This method will block until the video finishes playing + /// (and will continually update the window while doing so) + virtual void playVideo(const std::string& name, bool allowSkipping) = 0; + virtual void setNewGame(bool newgame) = 0; virtual void pushGuiMode (MWGui::GuiMode mode) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index bb6f5741d..f03a9197d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -420,8 +420,6 @@ namespace MWBase virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; /// \todo this does not belong here - virtual void playVideo(const std::string& name, bool allowSkipping) = 0; - virtual void stopVideo() = 0; virtual void frameStarted (float dt, bool paused) = 0; virtual void screenshot (Ogre::Image& image, int w, int h) = 0; diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 37e29591b..b3f70a5ab 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -226,7 +226,7 @@ namespace MWGui } mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - MWBase::Environment::get().getInputManager()->update(0, true); + MWBase::Environment::get().getInputManager()->update(0, true, true); // First, swap buffers from last draw, then, queue an update of the // window contents, but don't swap buffers (which would have diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 4ad260fd9..00e124f6c 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -13,6 +13,7 @@ #include "../mwstate/character.hpp" #include "savegamedialog.hpp" +#include "confirmationdialog.hpp" namespace MWGui { @@ -21,12 +22,13 @@ namespace MWGui : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0), mWidth (w), mHeight (h) , mSaveGameDialog(NULL) + , mBackground(NULL) { getWidget(mVersionText, "VersionText"); std::stringstream sstream; sstream << "OpenMW version: " << OPENMW_VERSION; - // adding info about git hash if availible + // adding info about git hash if available std::string rev = OPENMW_VERSION_COMMITHASH; std::string tag = OPENMW_VERSION_TAGHASH; if (!rev.empty() && !tag.empty()) @@ -58,10 +60,24 @@ namespace MWGui { if (visible) updateMenu(); + else + showBackground( + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && + MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame); OEngine::GUI::Layout::setVisible (visible); } + void MainMenu::onNewGameConfirmed() + { + MWBase::Environment::get().getStateManager()->newGame(); + } + + void MainMenu::onExitConfirmed() + { + MWBase::Environment::get().getStateManager()->requestQuit(); + } + void MainMenu::onButtonClicked(MyGUI::Widget *sender) { std::string name = *sender->getUserData(); @@ -73,11 +89,33 @@ namespace MWGui } else if (name == "options") MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); + else if (name == "credits") + MWBase::Environment::get().getWindowManager()->playVideo("mw_credits.bik", true); else if (name == "exitgame") - MWBase::Environment::get().getStateManager()->requestQuit(); + { + if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) + onExitConfirmed(); + else + { + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + dialog->open("#{sMessage2}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onExitConfirmed); + dialog->eventCancelClicked.clear(); + } + } else if (name == "newgame") { - MWBase::Environment::get().getStateManager()->newGame(); + if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) + onNewGameConfirmed(); + else + { + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + dialog->open("#{sNotifyMessage54}"); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onNewGameConfirmed); + dialog->eventCancelClicked.clear(); + } } else @@ -92,11 +130,42 @@ namespace MWGui } } + void MainMenu::showBackground(bool show) + { + if (mBackground) + { + MyGUI::Gui::getInstance().destroyWidget(mBackground); + mBackground = NULL; + } + if (show) + { + if (!mBackground) + { + mBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Stretch, "Menu"); + mBackground->setImageTexture("black.png"); + + // Use black bars to correct aspect ratio. The video player also does it, so we need to do it + // for mw_logo.bik to align correctly with menu_morrowind.dds. + MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // No way to un-hardcode this right now, menu_morrowind.dds is 1024x512 but was designed for 4:3 + double imageaspect = 4.0/3.0; + + int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * imageaspect) / 2); + int topPadding = std::max(0.0, (screenSize.height - screenSize.width / imageaspect) / 2); + + MyGUI::ImageBox* image = mBackground->createWidget("ImageBox", + leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2, MyGUI::Align::Default); + image->setImageTexture("textures\\menu_morrowind.dds"); + } + } + } + void MainMenu::updateMenu() { setCoord(0,0, mWidth, mHeight); - if (!mButtonBox) mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); @@ -104,6 +173,8 @@ namespace MWGui MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState(); + showBackground(state == MWBase::StateManager::State_NoGame); + std::vector buttons; if (state==MWBase::StateManager::State_Running) @@ -120,7 +191,10 @@ namespace MWGui buttons.push_back("savegame"); buttons.push_back("options"); - //buttons.push_back("credits"); + + if (state==MWBase::StateManager::State_NoGame) + buttons.push_back("credits"); + buttons.push_back("exitgame"); // Create new buttons if needed @@ -155,12 +229,27 @@ namespace MWGui assert(mButtons.find(*it) != mButtons.end()); MWGui::ImageButton* button = mButtons[*it]; button->setVisible(true); + MyGUI::IntSize requested = button->getRequestedSize(); - button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, requested.height); - curH += requested.height; + + // Trim off some of the excessive padding + // TODO: perhaps do this within ImageButton? + int trim = 8; + button->setImageCoord(MyGUI::IntCoord(0, trim, requested.width, requested.height-trim)); + int height = requested.height-trim*2; + button->setImageTile(MyGUI::IntSize(requested.width, height)); + button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, height); + curH += height; } - mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH); + if (state == MWBase::StateManager::State_NoGame) + { + // Align with the background image + int bottomPadding=48; + mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight - curH - bottomPadding, maxwidth, curH); + } + else + mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH); } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 722b329de..c571fda86 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -29,9 +29,15 @@ namespace MWGui MyGUI::Widget* mButtonBox; MyGUI::TextBox* mVersionText; + MyGUI::ImageBox* mBackground; + std::map mButtons; void onButtonClicked (MyGUI::Widget* sender); + void onNewGameConfirmed(); + void onExitConfirmed(); + + void showBackground(bool show); void updateMenu(); diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 50d53abac..a1688d2e5 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -47,9 +47,7 @@ namespace MWGui GM_Loading, GM_LoadingWallpaper, - GM_QuickKeysMenu, - - GM_Video + GM_QuickKeysMenu }; // Windows shown in inventory mode diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 77ad98121..caa082646 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -86,7 +86,21 @@ namespace MWGui { std::stringstream title; title << it->getSignature().mPlayerName; - title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")"; + + // For a custom class, we will not find it in the store (unless we loaded the savegame first). + // Fall back to name stored in savegame header in that case. + std::string className; + if (it->getSignature().mPlayerClassId.empty()) + className = it->getSignature().mPlayerClassName; + else + { + // Find the localised name for this class from the store + const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().find( + it->getSignature().mPlayerClassId); + className = class_->mName; + } + + title << " (Level " << it->getSignature().mPlayerLevel << " " << className << ")"; mCharacterSelection->addItem (title.str()); @@ -169,7 +183,10 @@ namespace MWGui else { if (mCurrentCharacter && slot) + { MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu); + } } setVisible(false); @@ -241,7 +258,13 @@ namespace MWGui struct tm* timeinfo; timeinfo = localtime(&time); - text << asctime(timeinfo) << "\n"; + // Use system/environment locale settings for datetime formatting + std::setlocale(LC_TIME, ""); + + const int size=1024; + char buffer[size]; + if (std::strftime(buffer, size, "%x %X", timeinfo) > 0) + text << buffer << "\n"; text << "Level " << slot->mProfile.mPlayerLevel << "\n"; text << slot->mProfile.mPlayerCell << "\n"; // text << "Time played: " << slot->mProfile.mTimePlayed << "\n"; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c99e2d0de..78adecd3e 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -83,91 +83,116 @@ namespace } return false; } + + const char* checkButtonType = "CheckButton"; + const char* sliderType = "Slider"; + + std::string getSettingType(MyGUI::Widget* widget) + { + return widget->getUserString("SettingType"); + } + + std::string getSettingName(MyGUI::Widget* widget) + { + return widget->getUserString("SettingName"); + } + + std::string getSettingCategory(MyGUI::Widget* widget) + { + return widget->getUserString("SettingCategory"); + } + + std::string getSettingValueType(MyGUI::Widget* widget) + { + return widget->getUserString("SettingValueType"); + } + + void getSettingMinMax(MyGUI::Widget* widget, float& min, float& max) + { + const char* settingMin = "SettingMin"; + const char* settingMax = "SettingMax"; + min = 0.f; + max = 1.f; + if (!widget->getUserString(settingMin).empty()) + min = boost::lexical_cast(widget->getUserString(settingMin)); + if (!widget->getUserString(settingMax).empty()) + max = boost::lexical_cast(widget->getUserString(settingMax)); + } } namespace MWGui { + void SettingsWindow::configureWidgets(MyGUI::Widget* widget) + { + MyGUI::EnumeratorWidgetPtr widgets = widget->getEnumerator(); + while (widgets.next()) + { + MyGUI::Widget* current = widgets.current(); + + std::string type = getSettingType(current); + if (type == checkButtonType) + { + std::string initialValue = Settings::Manager::getBool(getSettingName(current), + getSettingCategory(current)) + ? "#{sOn}" : "#{sOff}"; + current->castType()->setCaptionWithReplacing(initialValue); + current->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + } + if (type == sliderType) + { + MyGUI::ScrollBar* scroll = current->castType(); + if (getSettingValueType(current) == "Float") + { + // TODO: ScrollBar isn't meant for this. should probably use a dedicated FloatSlider widget + float min,max; + getSettingMinMax(scroll, min, max); + float value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + value = (value-min)/(max-min); + + scroll->setScrollPosition( value * (scroll->getScrollRange()-1)); + } + else + { + int value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + scroll->setScrollPosition(value); + } + scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + } + + configureWidgets(current); + } + } + SettingsWindow::SettingsWindow() : WindowBase("openmw_settings_window.layout") { + configureWidgets(mMainWidget); + getWidget(mOkButton, "OkButton"); - getWidget(mBestAttackButton, "BestAttackButton"); - getWidget(mGrabCursorButton, "GrabCursorButton"); - getWidget(mSubtitlesButton, "SubtitlesButton"); - getWidget(mCrosshairButton, "CrosshairButton"); getWidget(mResolutionList, "ResolutionList"); - getWidget(mMenuTransparencySlider, "MenuTransparencySlider"); - getWidget(mToolTipDelaySlider, "ToolTipDelaySlider"); - getWidget(mViewDistanceSlider, "ViewDistanceSlider"); getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mFPSButton, "FPSButton"); getWidget(mFOVSlider, "FOVSlider"); - getWidget(mMasterVolumeSlider, "MasterVolume"); - getWidget(mVoiceVolumeSlider, "VoiceVolume"); - getWidget(mEffectsVolumeSlider, "EffectsVolume"); - getWidget(mFootstepsVolumeSlider, "FootstepsVolume"); - getWidget(mMusicVolumeSlider, "MusicVolume"); getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); - getWidget(mWaterShaderButton, "WaterShaderButton"); - getWidget(mReflectObjectsButton, "ReflectObjectsButton"); - getWidget(mReflectActorsButton, "ReflectActorsButton"); - getWidget(mReflectTerrainButton, "ReflectTerrainButton"); getWidget(mShadersButton, "ShadersButton"); getWidget(mShaderModeButton, "ShaderModeButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); - getWidget(mShadowsLargeDistance, "ShadowsLargeDistance"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); - getWidget(mActorShadows, "ActorShadows"); - getWidget(mStaticsShadows, "StaticsShadows"); - getWidget(mMiscShadows, "MiscShadows"); - getWidget(mTerrainShadows, "TerrainShadows"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); - getWidget(mInvertYButton, "InvertYButton"); - getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); getWidget(mRefractionButton, "RefractionButton"); - mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mBestAttackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mGrabCursorButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mInvertYButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); - mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); - mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mRefractionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mReflectTerrainButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mReflectActorsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mTextureFilteringButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onTextureFilteringChanged); - mVSyncButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mFPSButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onFpsToggled); - mMenuTransparencySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mFOVSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mToolTipDelaySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); - mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mShadowsEnabledButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mShadowsLargeDistance->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); - mActorShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mStaticsShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mMiscShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - mTerrainShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); - - mMasterVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mVoiceVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mEffectsVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mFootstepsVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mMusicVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); center(); @@ -194,73 +219,25 @@ namespace MWGui mResolutionList->addItem(str); } - // read settings - int menu_transparency = (mMenuTransparencySlider->getScrollRange()-1) * Settings::Manager::getFloat("menu transparency", "GUI"); - mMenuTransparencySlider->setScrollPosition(menu_transparency); - int tooltip_delay = (mToolTipDelaySlider->getScrollRange()-1) * Settings::Manager::getFloat("tooltip delay", "GUI"); - mToolTipDelaySlider->setScrollPosition(tooltip_delay); - - mSubtitlesButton->setCaptionWithReplacing(Settings::Manager::getBool("subtitles", "GUI") ? "#{sOn}" : "#{sOff}"); - mCrosshairButton->setCaptionWithReplacing(Settings::Manager::getBool("crosshair", "HUD") ? "#{sOn}" : "#{sOff}"); - mBestAttackButton->setCaptionWithReplacing(Settings::Manager::getBool("best attack", "Game") ? "#{sOn}" : "#{sOff}"); - mGrabCursorButton->setCaptionWithReplacing(Settings::Manager::getBool("grab cursor", "Input") ? "#{sOn}" : "#{sOff}"); - - float fovVal = (Settings::Manager::getFloat("field of view", "General")-sFovMin)/(sFovMax-sFovMin); - mFOVSlider->setScrollPosition(fovVal * (mFOVSlider->getScrollRange()-1)); - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getFloat("field of view", "General"))) + ")"); - - float anisotropyVal = Settings::Manager::getInt("anisotropy", "General") / 16.0; - mAnisotropySlider->setScrollPosition(anisotropyVal * (mAnisotropySlider->getScrollRange()-1)); std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(Settings::Manager::getInt("anisotropy", "General")) + ")"); - float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-sViewDistMin)/(sViewDistMax-sViewDistMin); - int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; - mViewDistanceSlider->setScrollPosition(viewdist); - - mMasterVolumeSlider->setScrollPosition(Settings::Manager::getFloat("master volume", "Sound") * (mMasterVolumeSlider->getScrollRange()-1)); - mMusicVolumeSlider->setScrollPosition(Settings::Manager::getFloat("music volume", "Sound") * (mMusicVolumeSlider->getScrollRange()-1)); - mEffectsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("sfx volume", "Sound") * (mEffectsVolumeSlider->getScrollRange()-1)); - mFootstepsVolumeSlider->setScrollPosition(Settings::Manager::getFloat("footsteps volume", "Sound") * (mFootstepsVolumeSlider->getScrollRange()-1)); - mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1)); - - mWaterShaderButton->setCaptionWithReplacing(Settings::Manager::getBool("shader", "Water") ? "#{sOn}" : "#{sOff}"); - mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect statics", "Water") ? "#{sOn}" : "#{sOff}"); - mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}"); - mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); - mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); - - mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); - mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); - mStaticsShadows->setCaptionWithReplacing(Settings::Manager::getBool("statics shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); - mMiscShadows->setCaptionWithReplacing(Settings::Manager::getBool("misc shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); - mTerrainShadows->setCaptionWithReplacing(Settings::Manager::getBool("terrain shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); - - float cameraSens = (Settings::Manager::getFloat("camera sensitivity", "Input")-0.2)/(5.0-0.2); - mCameraSensitivitySlider->setScrollPosition (cameraSens * (mCameraSensitivitySlider->getScrollRange()-1)); - mCameraSensitivitySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); - - mShadersButton->setCaptionWithReplacing (Settings::Manager::getBool("shaders", "Objects") ? "#{sOn}" : "#{sOff}"); mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); - mRefractionButton->setCaptionWithReplacing (Settings::Manager::getBool("refraction", "Water") ? "#{sOn}" : "#{sOff}"); - if (!Settings::Manager::getBool("shaders", "Objects")) { mRefractionButton->setEnabled(false); mShadowsEnabledButton->setEnabled(false); } - mFullscreenButton->setCaptionWithReplacing(Settings::Manager::getBool("fullscreen", "Video") ? "#{sOn}" : "#{sOff}"); - mVSyncButton->setCaptionWithReplacing(Settings::Manager::getBool("vsync", "Video") ? "#{sOn}": "#{sOff}"); mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); + + MyGUI::TextBox* fovText; + getWidget(fovText, "FovText"); + fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getInt("field of view", "General"))) + ")"); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -320,6 +297,39 @@ namespace MWGui newState = true; } + if (_sender == mVSyncButton) + { + // Ogre::Window::setVSyncEnabled is bugged in 1.8 +#if OGRE_VERSION < (1 << 16 | 9 << 8 | 0) + MWBase::Environment::get().getWindowManager()-> + messageBox("VSync will be applied after a restart", std::vector()); +#endif + } + + if (_sender == mShadersButton) + { + if (newState == false) + { + // refraction needs shaders to display underwater fog + mRefractionButton->setCaptionWithReplacing("#{sOff}"); + mRefractionButton->setEnabled(false); + + Settings::Manager::setBool("refraction", "Water", false); + + // shadows not supported + mShadowsEnabledButton->setEnabled(false); + mShadowsEnabledButton->setCaptionWithReplacing("#{sOff}"); + Settings::Manager::setBool("enabled", "Shadows", false); + } + else + { + // re-enable + mRefractionButton->setEnabled(true); + + mShadowsEnabledButton->setEnabled(true); + } + } + if (_sender == mFullscreenButton) { // check if this resolution is supported in fullscreen @@ -341,64 +351,15 @@ namespace MWGui MWBase::Environment::get().getWindowManager()-> messageBox(msg); _sender->castType()->setCaption(off); + return; } - else - { - Settings::Manager::setBool("fullscreen", "Video", newState); - apply(); - } - } - else if (_sender == mVSyncButton) - { - Settings::Manager::setBool("vsync", "Video", newState); - // Ogre::Window::setVSyncEnabled is bugged in 1.8 -#if OGRE_VERSION < (1 << 16 | 9 << 8 | 0) - MWBase::Environment::get().getWindowManager()-> - messageBox("VSync will be applied after a restart", std::vector()); -#endif - apply(); } - else + + if (getSettingType(_sender) == checkButtonType) { - if (_sender == mVSyncButton) - Settings::Manager::setBool("vsync", "Video", newState); - if (_sender == mWaterShaderButton) - Settings::Manager::setBool("shader", "Water", newState); - else if (_sender == mRefractionButton) - Settings::Manager::setBool("refraction", "Water", newState); - else if (_sender == mReflectObjectsButton) - { - Settings::Manager::setBool("reflect misc", "Water", newState); - Settings::Manager::setBool("reflect statics", "Water", newState); - Settings::Manager::setBool("reflect statics small", "Water", newState); - } - else if (_sender == mReflectActorsButton) - Settings::Manager::setBool("reflect actors", "Water", newState); - else if (_sender == mReflectTerrainButton) - Settings::Manager::setBool("reflect terrain", "Water", newState); - else if (_sender == mShadowsEnabledButton) - Settings::Manager::setBool("enabled", "Shadows", newState); - else if (_sender == mShadowsLargeDistance) - Settings::Manager::setBool("split", "Shadows", newState); - else if (_sender == mActorShadows) - Settings::Manager::setBool("actor shadows", "Shadows", newState); - else if (_sender == mStaticsShadows) - Settings::Manager::setBool("statics shadows", "Shadows", newState); - else if (_sender == mMiscShadows) - Settings::Manager::setBool("misc shadows", "Shadows", newState); - else if (_sender == mTerrainShadows) - Settings::Manager::setBool("terrain shadows", "Shadows", newState); - else if (_sender == mInvertYButton) - Settings::Manager::setBool("invert y axis", "Input", newState); - else if (_sender == mCrosshairButton) - Settings::Manager::setBool("crosshair", "HUD", newState); - else if (_sender == mSubtitlesButton) - Settings::Manager::setBool("subtitles", "GUI", newState); - else if (_sender == mBestAttackButton) - Settings::Manager::setBool("best attack", "Game", newState); - else if (_sender == mGrabCursorButton) - Settings::Manager::setBool("grab cursor", "Input", newState); + Settings::Manager::setBool(getSettingName(_sender), getSettingCategory(_sender), newState); apply(); + return; } } @@ -419,50 +380,6 @@ namespace MWGui apply(); } - void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) - { - std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); - std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); - - std::string val = static_cast(_sender)->getCaption(); - if (val == off) - val = on; - else - val = off; - static_cast(_sender)->setCaptionWithReplacing (val); - - if (val == off) - { - Settings::Manager::setBool("shaders", "Objects", false); - - // refraction needs shaders to display underwater fog - mRefractionButton->setCaptionWithReplacing("#{sOff}"); - mRefractionButton->setEnabled(false); - - Settings::Manager::setBool("refraction", "Water", false); - Settings::Manager::setBool("underwater effect", "Water", false); - - // shadows not supported - mShadowsEnabledButton->setEnabled(false); - mShadowsEnabledButton->setCaptionWithReplacing("#{sOff}"); - Settings::Manager::setBool("enabled", "Shadows", false); - } - else - { - Settings::Manager::setBool("shaders", "Objects", true); - - // re-enable - mReflectObjectsButton->setEnabled(true); - mReflectActorsButton->setEnabled(true); - mReflectTerrainButton->setEnabled(true); - mRefractionButton->setEnabled(true); - - mShadowsEnabledButton->setEnabled(true); - } - - apply(); - } - void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 3; @@ -479,39 +396,34 @@ namespace MWGui void SettingsWindow::onSliderChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { - float val = pos / float(scroller->getScrollRange()-1); - if (scroller == mMenuTransparencySlider) - Settings::Manager::setFloat("menu transparency", "GUI", val); - else if (scroller == mToolTipDelaySlider) - Settings::Manager::setFloat("tooltip delay", "GUI", val); - else if (scroller == mViewDistanceSlider) - Settings::Manager::setFloat("max viewing distance", "Viewing distance", (1-val) * sViewDistMin + val * sViewDistMax); - else if (scroller == mFOVSlider) + if (getSettingType(scroller) == "Slider") { - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + boost::lexical_cast(int((1-val) * sFovMin + val * sFovMax)) + ")"); - Settings::Manager::setFloat("field of view", "General", (1-val) * sFovMin + val * sFovMax); - } - else if (scroller == mAnisotropySlider) - { - mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(int(val*16)) + ")"); - Settings::Manager::setInt("anisotropy", "General", val * 16); + if (getSettingValueType(scroller) == "Float") + { + float value = pos / float(scroller->getScrollRange()-1); + + float min,max; + getSettingMinMax(scroller, min, max); + value = min + (max-min) * value; + Settings::Manager::setFloat(getSettingName(scroller), getSettingCategory(scroller), value); + + if (scroller == mFOVSlider) + { + MyGUI::TextBox* fovText; + getWidget(fovText, "FovText"); + fovText->setCaption("Field of View (" + boost::lexical_cast(int(value)) + ")"); + } + } + else + { + Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), pos); + if (scroller == mAnisotropySlider) + { + mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(pos) + ")"); + } + } + apply(); } - else if (scroller == mMasterVolumeSlider) - Settings::Manager::setFloat("master volume", "Sound", val); - else if (scroller == mVoiceVolumeSlider) - Settings::Manager::setFloat("voice volume", "Sound", val); - else if (scroller == mEffectsVolumeSlider) - Settings::Manager::setFloat("sfx volume", "Sound", val); - else if (scroller == mFootstepsVolumeSlider) - Settings::Manager::setFloat("footsteps volume", "Sound", val); - else if (scroller == mMusicVolumeSlider) - Settings::Manager::setFloat("music volume", "Sound", val); - else if (scroller == mCameraSensitivitySlider) - Settings::Manager::setFloat("camera sensitivity", "Input", (1-val) * 0.2 + val * 5.f); - - apply(); } void SettingsWindow::apply() diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 6b9ce414b..7a6c1a5ed 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -19,61 +19,29 @@ namespace MWGui void updateControlsBox(); - private: - static int const sFovMin = 30; - static int const sFovMax = 140; - static int const sViewDistMin = 2000; - static int const sViewDistMax = 5600; - - protected: + protected: MyGUI::Button* mOkButton; - MyGUI::ScrollBar* mMenuTransparencySlider; - MyGUI::ScrollBar* mToolTipDelaySlider; - MyGUI::Button* mSubtitlesButton; - MyGUI::Button* mCrosshairButton; - MyGUI::Button* mBestAttackButton; - MyGUI::Button* mGrabCursorButton; - // graphics MyGUI::ListBox* mResolutionList; MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mFPSButton; - MyGUI::ScrollBar* mViewDistanceSlider; MyGUI::ScrollBar* mFOVSlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::ComboBox* mTextureFilteringButton; MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; - MyGUI::Button* mWaterShaderButton; - MyGUI::Button* mReflectObjectsButton; - MyGUI::Button* mReflectActorsButton; - MyGUI::Button* mReflectTerrainButton; MyGUI::Button* mShadersButton; MyGUI::Button* mShaderModeButton; MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; - MyGUI::Button* mShadowsLargeDistance; MyGUI::ComboBox* mShadowsTextureSize; - MyGUI::Button* mActorShadows; - MyGUI::Button* mStaticsShadows; - MyGUI::Button* mMiscShadows; - MyGUI::Button* mTerrainShadows; - - // audio - MyGUI::ScrollBar* mMasterVolumeSlider; - MyGUI::ScrollBar* mVoiceVolumeSlider; - MyGUI::ScrollBar* mEffectsVolumeSlider; - MyGUI::ScrollBar* mFootstepsVolumeSlider; - MyGUI::ScrollBar* mMusicVolumeSlider; // controls MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; - MyGUI::Button* mInvertYButton; - MyGUI::ScrollBar* mCameraSensitivitySlider; void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); @@ -84,7 +52,6 @@ namespace MWGui void onResolutionAccept(); void onResolutionCancel(); - void onShadersToggled(MyGUI::Widget* _sender); void onShaderModeToggled(MyGUI::Widget* _sender); void onShadowTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); @@ -94,6 +61,8 @@ namespace MWGui void onResetDefaultBindingsAccept (); void apply(); + + void configureWidgets(MyGUI::Widget* widget); }; } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp new file mode 100644 index 000000000..566c7cadb --- /dev/null +++ b/apps/openmw/mwgui/videowidget.cpp @@ -0,0 +1,45 @@ +#include "videowidget.hpp" + +namespace MWGui +{ + +VideoWidget::VideoWidget() + : mAllowSkipping(true) +{ + eventKeyButtonPressed += MyGUI::newDelegate(this, &VideoWidget::onKeyPressed); + + setNeedKeyFocus(true); +} + +void VideoWidget::playVideo(const std::string &video, bool allowSkipping) +{ + mAllowSkipping = allowSkipping; + + mPlayer.playVideo(video); + + setImageTexture(mPlayer.getTextureName()); +} + +int VideoWidget::getVideoWidth() +{ + return mPlayer.getVideoWidth(); +} + +int VideoWidget::getVideoHeight() +{ + return mPlayer.getVideoHeight(); +} + +void VideoWidget::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char) +{ + if (_key == MyGUI::KeyCode::Escape && mAllowSkipping) + mPlayer.stopVideo(); +} + +bool VideoWidget::update() +{ + mPlayer.update(); + return mPlayer.isPlaying(); +} + +} diff --git a/apps/openmw/mwgui/videowidget.hpp b/apps/openmw/mwgui/videowidget.hpp new file mode 100644 index 000000000..16a71d367 --- /dev/null +++ b/apps/openmw/mwgui/videowidget.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_MWGUI_VIDEOWIDGET_H +#define OPENMW_MWGUI_VIDEOWIDGET_H + +#include + +#include "../mwrender/videoplayer.hpp" + +namespace MWGui +{ + + /** + * Widget that plays a video. Can be skipped by pressing Esc. + */ + class VideoWidget : public MyGUI::ImageBox + { + public: + MYGUI_RTTI_DERIVED(VideoWidget) + + VideoWidget(); + + void playVideo (const std::string& video, bool allowSkipping); + + int getVideoWidth(); + int getVideoHeight(); + + /// @return Is the video still playing? + bool update(); + + private: + bool mAllowSkipping; + + MWRender::VideoPlayer mPlayer; + + void onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1b71157a7..1e019aaa9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "MyGUI_UString.h" #include "MyGUI_IPointer.h" @@ -59,6 +60,7 @@ #include "bookpage.hpp" #include "itemview.hpp" #include "fontloader.hpp" +#include "videowidget.hpp" namespace MWGui { @@ -104,6 +106,8 @@ namespace MWGui , mRecharge(NULL) , mRepair(NULL) , mCompanionWindow(NULL) + , mVideoBackground(NULL) + , mVideoWidget(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -155,6 +159,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); @@ -186,6 +191,13 @@ namespace MWGui // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); + + mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal("ImageBox", 0,0,1,1, + MyGUI::Align::Default, "Overlay"); + mVideoBackground->setImageTexture("black.png"); + mVideoBackground->setVisible(false); + + mVideoWidget = mVideoBackground->createWidgetReal("ImageBox", 0,0,1,1, MyGUI::Align::Default); } void WindowManager::initUI() @@ -391,6 +403,7 @@ namespace MWGui mCompanionWindow->setVisible(false); mInventoryWindow->setTrading(false); mRecharge->setVisible(false); + mVideoBackground->setVisible(false); mHud->setVisible(mHudEnabled); @@ -539,10 +552,6 @@ namespace MWGui setCursorVisible(false); break; - case GM_Video: - setCursorVisible(false); - mHud->setVisible(false); - break; default: // Unsupported mode, switch back to game break; @@ -894,6 +903,7 @@ namespace MWGui void WindowManager::windowResized(int x, int y) { + sizeVideo(x, y); mGuiManager->windowResized(); mLoadingScreen->onResChange (x,y); if (!mHud) @@ -1401,4 +1411,57 @@ namespace MWGui mMap->readRecord(reader, type); } + void WindowManager::playVideo(const std::string &name, bool allowSkipping) + { + mVideoWidget->playVideo("video\\" + name, allowSkipping); + + // Turn off all rendering except for the GUI + mRendering->getScene()->clearSpecialCaseRenderQueues(); + // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work? + for(int i = 0;i < Ogre::RENDER_QUEUE_MAX;++i) + { + if(i > 0 && i < 96) + mRendering->getScene()->addSpecialCaseRenderQueue(i); + } + mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + + MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize(); + sizeVideo(screenSize.width, screenSize.height); + + setKeyFocusWidget(mVideoWidget); + + mVideoBackground->setVisible(true); + + bool cursorWasVisible = mCursorVisible; + setCursorVisible(false); + + while (mVideoWidget->update()) + { + MWBase::Environment::get().getInputManager()->update(0, true, false); + + mRendering->getWindow()->update(); + } + + setCursorVisible(cursorWasVisible); + + // Restore normal rendering + mRendering->getScene()->clearSpecialCaseRenderQueues(); + mRendering->getScene()->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + + mVideoBackground->setVisible(false); + } + + void WindowManager::sizeVideo(int screenWidth, int screenHeight) + { + // Use black bars to correct aspect ratio + mVideoBackground->setSize(screenWidth, screenHeight); + + double imageaspect = static_cast(mVideoWidget->getVideoWidth())/mVideoWidget->getVideoHeight(); + + int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2); + int topPadding = std::max(0.0, (screenHeight - screenWidth / imageaspect) / 2); + + mVideoWidget->setCoord(leftPadding, topPadding, + screenWidth - leftPadding*2, screenHeight - topPadding*2); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index dafb65e47..ab9770a41 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -18,6 +18,7 @@ namespace MyGUI class Widget; class Window; class UString; + class ImageBox; } namespace Compiler @@ -80,6 +81,7 @@ namespace MWGui class SoulgemDialog; class Recharge; class CompanionWindow; + class VideoWidget; class WindowManager : public MWBase::WindowManager { @@ -98,6 +100,10 @@ namespace MWGui virtual Loading::Listener* getLoadingScreen(); + /// @note This method will block until the video finishes playing + /// (and will continually update the window while doing so) + virtual void playVideo(const std::string& name, bool allowSkipping); + /** * Should be called each frame to update windows/gui elements. * This could mean updating sizes of gui elements or opening @@ -332,6 +338,8 @@ namespace MWGui Repair* mRepair; Recharge* mRecharge; CompanionWindow* mCompanionWindow; + MyGUI::ImageBox* mVideoBackground; + VideoWidget* mVideoWidget; Translation::Storage& mTranslationDataStorage; Cursor* mSoftwareCursor; @@ -390,6 +398,8 @@ namespace MWGui void onCursorChange(const std::string& name); void onKeyFocusChanged(MyGUI::Widget* widget); + + void sizeVideo(int screenWidth, int screenHeight); }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4bfd3f465..e2d4f8cb2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -96,12 +96,12 @@ namespace MWInput : mOgre(ogre) , mPlayer(NULL) , mEngine(engine) - , mMouseLookEnabled(true) + , mMouseLookEnabled(false) , mMouseX(ogre.getWindow()->getWidth ()/2.f) , mMouseY(ogre.getWindow()->getHeight ()/2.f) , mMouseWheel(0) , mDragDrop(false) - , mGuiCursorEnabled(false) + , mGuiCursorEnabled(true) , mUserFile(userFile) , mUserFileExists(userFileExists) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) @@ -256,18 +256,21 @@ namespace MWInput } } - void InputManager::update(float dt, bool loading) + void InputManager::update(float dt, bool disableControls, bool disableEvents) { mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); - mInputManager->capture(loading); + mInputManager->capture(disableEvents); // inject some fake mouse movement to force updating MyGUI's widget states MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); // update values of channels (as a result of pressed keys) - if (!loading) + if (!disableControls) mInputBinder->update(dt); + if (disableControls) + return; + bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console; @@ -288,9 +291,6 @@ namespace MWInput mInputManager->warpMouse(mMouseX, mMouseY); } - if (loading) - return; - // Disable movement in Gui mode if (MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running) @@ -626,9 +626,7 @@ namespace MWInput if (MyGUI::InputManager::getInstance ().isModalAny()) return; - if (MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_Video) - MWBase::Environment::get().getWorld ()->stopVideo (); - else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)) + if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)) { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getSoundManager()->resumeSounds (MWBase::SoundManager::Play_TypeSfx); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 2eab03a34..87fbda25c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -68,7 +68,7 @@ namespace MWInput /// Clear all savegame-specific data virtual void clear(); - virtual void update(float dt, bool loading); + virtual void update(float dt, bool disableControls, bool disableEvents=false); void setPlayer (MWWorld::Player* player) { mPlayer = player; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2db3bacf0..93c789af1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -414,6 +414,16 @@ void CharacterController::playRandomDeath(float startpoint) mDeathState = CharState_SwimDeath; mCurrentDeath = "swimdeath"; } + else if (mHitState == CharState_KnockDown) + { + mDeathState = CharState_DeathKnockDown; + mCurrentDeath = "deathknockdown"; + } + else if (mHitState == CharState_KnockOut) + { + mDeathState = CharState_DeathKnockOut; + mCurrentDeath = "deathknockout"; + } else { int selected=0; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4009744ef..5aea0210f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -90,6 +90,8 @@ enum CharacterState { CharState_Death4, CharState_Death5, CharState_SwimDeath, + CharState_DeathKnockDown, + CharState_DeathKnockOut, CharState_Hit, CharState_KnockDown, diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4c8f35edb..3164ca155 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -750,9 +750,10 @@ namespace MWMechanics mActors.updateMagicEffects(ptr); } - void MechanicsManager::toggleAI() + bool MechanicsManager::toggleAI() { mAI = !mAI; + return mAI; } bool MechanicsManager::isAIActive() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 761caf586..5dd758377 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -137,7 +137,7 @@ namespace MWMechanics virtual std::list getActorsFollowing(const MWWorld::Ptr& actor); - virtual void toggleAI(); + virtual bool toggleAI(); virtual bool isAIActive(); virtual void playerLoaded(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 15d56b8a9..fa7b17a7c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -43,7 +43,6 @@ #include "water.hpp" #include "npcanimation.hpp" #include "globalmap.hpp" -#include "videoplayer.hpp" #include "terrainstorage.hpp" #include "effectmanager.hpp" @@ -171,9 +170,6 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - mVideoPlayer = new VideoPlayer(mRendering.getScene (), mRendering.getWindow()); - mVideoPlayer->setResolution (Settings::Manager::getInt ("resolution x", "Video"), Settings::Manager::getInt ("resolution y", "Video")); - mSun = 0; mDebugging = new Debugging(mRootNode, engine); @@ -197,7 +193,6 @@ RenderingManager::~RenderingManager () delete mLocalMap; delete mOcclusionQuery; delete mWater; - delete mVideoPlayer; delete mActors; delete mObjects; delete mEffectManager; @@ -333,8 +328,6 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) void RenderingManager::update (float duration, bool paused) { - mVideoPlayer->update (); - if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; @@ -884,8 +877,6 @@ void RenderingManager::windowResized(int x, int y) Settings::Manager::setInt("resolution y", "Video", y); mRendering.adjustViewport(); - mVideoPlayer->setResolution (x, y); - MWBase::Environment::get().getWindowManager()->windowResized(x,y); } @@ -1001,16 +992,6 @@ void RenderingManager::screenshot(Image &image, int w, int h) mRendering.getCamera()->setAspectRatio(oldAspect); } -void RenderingManager::playVideo(const std::string& name, bool allowSkipping) -{ - mVideoPlayer->playVideo ("video/" + name, allowSkipping); -} - -void RenderingManager::stopVideo() -{ - mVideoPlayer->stopVideo (); -} - void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mWater->addEmitter (ptr, scale, force); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 115a94786..423a7078a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -46,7 +46,6 @@ namespace MWRender class LocalMap; class Water; class GlobalMap; - class VideoPlayer; class Animation; class EffectManager; @@ -209,8 +208,6 @@ public: Animation* getAnimation(const MWWorld::Ptr &ptr); - void playVideo(const std::string& name, bool allowSkipping); - void stopVideo(); void frameStarted(float dt, bool paused); void screenshot(Ogre::Image& image, int w, int h); @@ -271,8 +268,6 @@ private: MWRender::LocalMap* mLocalMap; MWRender::Shadows* mShadows; - - VideoPlayer* mVideoPlayer; }; } diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index f3c0971e7..80704ca7c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,7 +17,6 @@ #include -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwsound/sound_decoder.hpp" @@ -126,7 +125,7 @@ struct VideoState { int stream_open(int stream_index, AVFormatContext *pFormatCtx); - bool update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height); + bool update(); static void video_thread_loop(VideoState *is); static void decode_thread_loop(VideoState *is); @@ -163,6 +162,7 @@ struct VideoState { static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); + Ogre::TexturePtr mTexture; Ogre::DataStreamPtr stream; AVFormatContext* format_ctx; @@ -599,22 +599,17 @@ void VideoState::video_display() if((*this->video_st)->codec->width != 0 && (*this->video_st)->codec->height != 0) { - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("VideoTexture"); - if(texture.isNull() || static_cast(texture->getWidth()) != (*this->video_st)->codec->width - || static_cast(texture->getHeight()) != (*this->video_st)->codec->height) + + if(static_cast(mTexture->getWidth()) != (*this->video_st)->codec->width || + static_cast(mTexture->getHeight()) != (*this->video_st)->codec->height) { - Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); - texture = Ogre::TextureManager::getSingleton().createManual( - "VideoTexture", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - (*this->video_st)->codec->width, (*this->video_st)->codec->height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + mTexture->unload(); + mTexture->setWidth((*this->video_st)->codec->width); + mTexture->setHeight((*this->video_st)->codec->height); + mTexture->createInternalResources(); } Ogre::PixelBox pb((*this->video_st)->codec->width, (*this->video_st)->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); - Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); + Ogre::HardwarePixelBufferSharedPtr buffer = mTexture->getBuffer(); buffer->blitFromMemory(pb); this->display_ready = true; } @@ -851,7 +846,7 @@ void VideoState::decode_thread_loop(VideoState *self) } -bool VideoState::update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height) +bool VideoState::update() { if(this->quit) return false; @@ -860,21 +855,6 @@ bool VideoState::update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int scr { this->refresh = false; this->video_refresh_timer(); - // Would be nice not to do this all the time... - if(this->display_ready) - mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); - - // Correct aspect ratio by adding black bars - double videoaspect = av_q2d((*this->video_st)->codec->sample_aspect_ratio); - if(videoaspect == 0.0) - videoaspect = 1.0; - videoaspect *= static_cast((*this->video_st)->codec->width) / (*this->video_st)->codec->height; - - double screenaspect = static_cast(screen_width) / screen_height; - double aspect_correction = videoaspect / screenaspect; - - rect->setCorners(std::max(-1.0, -1.0 * aspect_correction), std::min( 1.0, 1.0 / aspect_correction), - std::min( 1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); } return true; } @@ -994,12 +974,36 @@ void VideoState::init(const std::string& resourceName) audio_index = i; } + if (audio_index != -1) + MWBase::Environment::get().getSoundManager()->pauseSounds(); + this->external_clock_base = av_gettime(); if(audio_index >= 0) this->stream_open(audio_index, this->format_ctx); if(video_index >= 0) + { this->stream_open(video_index, this->format_ctx); + int width = (*this->video_st)->codec->width; + int height = (*this->video_st)->codec->height; + static int i = 0; + this->mTexture = Ogre::TextureManager::getSingleton().createManual( + "OpenMW/VideoTexture" + Ogre::StringConverter::toString(++i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + width, height, // TEST + 0, + Ogre::PF_BYTE_RGBA, + Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + + // initialize to (0,0,0,0) + std::vector buffer; + buffer.resize(width * height, 0); + Ogre::PixelBox pb(width, height, 1, Ogre::PF_BYTE_RGBA, &buffer[0]); + this->mTexture->getBuffer()->blitFromMemory(pb); + } + + this->parse_thread = boost::thread(decode_thread_loop, this); } @@ -1070,113 +1074,26 @@ public: #endif // defined OPENMW_USE_FFMPEG -VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* window) +VideoPlayer::VideoPlayer() : mState(NULL) - , mSceneMgr(sceneMgr) - , mRectangle(NULL) - , mNode(NULL) - , mAllowSkipping(false) - , mWindow(window) - , mWidth(0) - , mHeight(0) { - mVideoMaterial = Ogre::MaterialManager::getSingleton().getByName("VideoMaterial", "General"); - if (mVideoMaterial.isNull ()) - { - mVideoMaterial = Ogre::MaterialManager::getSingleton().create("VideoMaterial", "General"); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); - } - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); - Ogre::MaterialPtr blackMaterial = Ogre::MaterialManager::getSingleton().getByName("BlackBarsMaterial", "General"); - if (blackMaterial.isNull ()) - { - blackMaterial = Ogre::MaterialManager::getSingleton().create("BlackBarsMaterial", "General"); - blackMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - blackMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - blackMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - blackMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); - } - - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); - mRectangle->setMaterial("VideoMaterial"); - mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+2); - mBackgroundRectangle = new Ogre::Rectangle2D(true); - mBackgroundRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); - mBackgroundRectangle->setMaterial("BlackBarsMaterial"); - mBackgroundRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); - - // Use infinite AAB to always stay visible - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - mRectangle->setBoundingBox(aabInf); - mBackgroundRectangle->setBoundingBox(aabInf); - - // Attach background to the scene - mNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); - mNode->attachObject(mRectangle); - mBackgroundNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); - mBackgroundNode->attachObject(mBackgroundRectangle); - - mRectangle->setVisible(false); - mRectangle->setVisibilityFlags(RV_Overlay); - mBackgroundRectangle->setVisible(false); - mBackgroundRectangle->setVisibilityFlags(RV_Overlay); } VideoPlayer::~VideoPlayer() { if(mState) close(); - - mSceneMgr->destroySceneNode(mNode); - mSceneMgr->destroySceneNode(mBackgroundNode); - - delete mRectangle; - delete mBackgroundRectangle; } -void VideoPlayer::playVideo(const std::string &resourceName, bool allowSkipping) +void VideoPlayer::playVideo(const std::string &resourceName) { - mAllowSkipping = allowSkipping; - if(mState) close(); - mRectangle->setVisible(true); - mBackgroundRectangle->setVisible(true); - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); - - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Video); - - // 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 > 0 && i < 96) - mSceneMgr->addSpecialCaseRenderQueue(i); - } - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - - MWBase::Environment::get().getSoundManager()->pauseSounds(); - try { mState = new VideoState; mState->init(resourceName); - - while (isPlaying()) - { - MWBase::Environment::get().getInputManager()->update(0, false); - update(); - mWindow->update(); - } - } catch(std::exception& e) { std::cerr<< "Failed to play video: "<update(mVideoMaterial, mRectangle, mWidth, mHeight)) + if(!mState->update()) close(); } } +std::string VideoPlayer::getTextureName() +{ + std::string name; + if (mState) + name = mState->mTexture->getName(); + return name; +} + +int VideoPlayer::getVideoWidth() +{ + int width=0; + if (mState) + width = mState->mTexture->getWidth(); + return width; +} + +int VideoPlayer::getVideoHeight() +{ + int height=0; + if (mState) + height = mState->mTexture->getHeight(); + return height; +} + void VideoPlayer::stopVideo () { - if (mAllowSkipping) - close(); + close(); } void VideoPlayer::close() @@ -1210,13 +1150,6 @@ void VideoPlayer::close() } MWBase::Environment::get().getSoundManager()->resumeSounds(); - - mRectangle->setVisible(false); - mBackgroundRectangle->setVisible(false); - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Video); - - mSceneMgr->clearSpecialCaseRenderQueues(); - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); } bool VideoPlayer::isPlaying () diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 0e548e23e..47e252cc1 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -1,27 +1,22 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H -#include - -namespace Ogre -{ - class SceneManager; - class SceneNode; - class Rectangle2D; - class RenderWindow; -} +#include namespace MWRender { struct VideoState; + /** + * @brief Plays a video on an Ogre texture. + */ class VideoPlayer { public: - VideoPlayer(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* window); + VideoPlayer(); ~VideoPlayer(); - void playVideo (const std::string& resourceName, bool allowSkipping); + void playVideo (const std::string& resourceName); void update(); @@ -30,22 +25,14 @@ namespace MWRender bool isPlaying(); - void setResolution (int w, int h) { mWidth = w; mHeight = h; } + std::string getTextureName(); + int getVideoWidth(); + int getVideoHeight(); private: VideoState* mState; - bool mAllowSkipping; - - Ogre::SceneManager* mSceneMgr; - Ogre::MaterialPtr mVideoMaterial; - Ogre::Rectangle2D* mRectangle; - Ogre::Rectangle2D* mBackgroundRectangle; - Ogre::SceneNode* mNode; - Ogre::SceneNode* mBackgroundNode; - Ogre::RenderWindow* mWindow; - int mWidth; int mHeight; }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1fa5d8834..5368cbe68 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -418,10 +418,8 @@ void Water::applyRTT() void Water::applyVisibilityMask() { mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") - + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") - + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") + + (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water") + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + RV_Sky; if (mReflection) @@ -444,8 +442,6 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin if ( it->first == "Water" && ( it->second == "reflect actors" || it->second == "reflect terrain" - || it->second == "reflect misc" - || it->second == "reflect small statics" || it->second == "reflect statics")) applyVisMask = true; } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 8314d011a..a34c5476c 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -464,7 +464,12 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWBase::Environment::get().getMechanicsManager()->toggleAI(); + InterpreterContext& context + = static_cast (runtime.getContext()); + + bool enabled = MWBase::Environment::get().getMechanicsManager()->toggleAI(); + + context.report (enabled ? "AI -> On" : "AI -> Off"); } }; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index fa8441aa5..89a5ceec1 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -47,7 +47,7 @@ namespace MWScript bool allowSkipping = runtime[0].mInteger; runtime.pop(); - MWBase::Environment::get().getWorld ()->playVideo (name, allowSkipping); + MWBase::Environment::get().getWindowManager()->playVideo (name, allowSkipping); } }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 5430caae5..6b0871012 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -156,7 +156,12 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot profile.mPlayerName = player.getClass().getName (player); profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); - profile.mPlayerClass = player.get()->mBase->mClass; + + std::string classId = player.get()->mBase->mClass; + if (world.getStore().get().isDynamic(classId)) + profile.mPlayerClassName = world.getStore().get().find(classId)->mName; + else + profile.mPlayerClassId = classId; profile.mPlayerCell = world.getCellName(); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 6b99c0a0c..0fc2d547c 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -157,6 +157,14 @@ namespace MWWorld return 0; } + /** + * Does the record with this ID come from the dynamic store? + */ + bool isDynamic(const std::string &id) const { + typename Dynamic::const_iterator dit = mDynamic.find(id); + return (dit != mDynamic.end()); + } + /** Returns a random record that starts with the named ID, or NULL if not found. */ const T *searchRandom(const std::string &id) const { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 81afc394a..594a9f7f4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1305,7 +1305,7 @@ namespace MWWorld { --mPlayIntro; if (mPlayIntro == 0) - mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); + MWBase::Environment::get().getWindowManager()->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); } if (mGoToJail && !paused) @@ -1776,16 +1776,6 @@ namespace MWWorld return mRendering->getAnimation(ptr); } - void World::playVideo (const std::string &name, bool allowSkipping) - { - mRendering->playVideo(name, allowSkipping); - } - - void World::stopVideo () - { - mRendering->stopVideo(); - } - void World::frameStarted (float dt, bool paused) { mRendering->frameStarted(dt, paused); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 42f52cb61..f1e89bf6b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -523,8 +523,6 @@ namespace MWWorld virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); /// \todo this does not belong here - virtual void playVideo(const std::string& name, bool allowSkipping); - virtual void stopVideo(); virtual void frameStarted (float dt, bool paused); virtual void screenshot (Ogre::Image& image, int w, int h); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 5457d7625..98bd63ba1 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -86,7 +86,7 @@ namespace Compiler { if (mState==PotentialEndState) { - getErrorHandler().warning ("stay string argument (ignoring it)", loc); + getErrorHandler().warning ("stray string argument (ignoring it)", loc); mState = EndState; return true; } @@ -377,19 +377,19 @@ namespace Compiler case Scanner::K_else: - getErrorHandler().warning ("stay else (ignoring it)", loc); + getErrorHandler().warning ("stray else (ignoring it)", loc); mState = EndState; return true; case Scanner::K_endif: - getErrorHandler().warning ("stay endif (ignoring it)", loc); + getErrorHandler().warning ("stray endif (ignoring it)", loc); mState = EndState; return true; case Scanner::K_begin: - getErrorHandler().warning ("stay begin (ignoring it)", loc); + getErrorHandler().warning ("stray begin (ignoring it)", loc); mState = EndState; return true; } diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index d6887f170..b5e0810db 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -11,7 +11,10 @@ void ESM::SavedGame::load (ESMReader &esm) { mPlayerName = esm.getHNString("PLNA"); esm.getHNOT (mPlayerLevel, "PLLE"); - mPlayerClass = esm.getHNString("PLCL"); + + mPlayerClassId = esm.getHNOString("PLCL"); + mPlayerClassName = esm.getHNOString("PLCN"); + mPlayerCell = esm.getHNString("PLCE"); esm.getHNT (mInGameTime, "TSTM", 16); esm.getHNT (mTimePlayed, "TIME"); @@ -30,7 +33,12 @@ void ESM::SavedGame::save (ESMWriter &esm) const { esm.writeHNString ("PLNA", mPlayerName); esm.writeHNT ("PLLE", mPlayerLevel); - esm.writeHNString ("PLCL", mPlayerClass); + + if (!mPlayerClassId.empty()) + esm.writeHNString ("PLCL", mPlayerClassId); + else + esm.writeHNString ("PLCN", mPlayerClassName); + esm.writeHNString ("PLCE", mPlayerCell); esm.writeHNT ("TSTM", mInGameTime, 16); esm.writeHNT ("TIME", mTimePlayed); diff --git a/components/esm/savedgame.hpp b/components/esm/savedgame.hpp index 9c7bf551d..3e7cae775 100644 --- a/components/esm/savedgame.hpp +++ b/components/esm/savedgame.hpp @@ -26,7 +26,13 @@ namespace ESM std::vector mContentFiles; std::string mPlayerName; int mPlayerLevel; - std::string mPlayerClass; // this is the ID and not the name of the class + + // ID of class + std::string mPlayerClassId; + // Name of the class. When using a custom class, the ID is not really meaningful prior + // to loading the savegame, so the name is stored separately. + std::string mPlayerClassName; + std::string mPlayerCell; TimeStamp mInGameTime; double mTimePlayed; diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 84ec6f7c5..e66f3fc01 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,13 +1,14 @@ - + + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 61103963d..adf9f1557 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -18,6 +18,10 @@ + + + + @@ -34,6 +38,10 @@ + + + + @@ -45,28 +53,44 @@ - + + + + + - + + + + + - + + + + + - + + + + + @@ -81,6 +105,10 @@ + + + + @@ -89,6 +117,10 @@ + + + + @@ -97,6 +129,10 @@ + + + + @@ -105,6 +141,10 @@ + + + + @@ -113,6 +153,10 @@ + + + + @@ -127,7 +171,11 @@ - + + + + + @@ -139,6 +187,12 @@ + + + + + + @@ -149,8 +203,6 @@ - - @@ -163,16 +215,23 @@ - - + + + + + - + + + + + @@ -186,7 +245,11 @@ - + + + + + @@ -205,6 +268,12 @@ + + + + + + @@ -233,8 +302,10 @@ - - + + + + @@ -244,6 +315,12 @@ + + + + + + @@ -260,7 +337,11 @@ - + + + + + @@ -269,21 +350,33 @@ - + + + + + - + + + + + - + + + + + @@ -291,7 +384,11 @@ - + + + + + @@ -302,7 +399,11 @@ - + + + + + @@ -311,35 +412,52 @@ - + + + + + - - - + + + + - + + + + + - + + + + + - + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4fb7097f8..6361476e3 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -8,6 +8,9 @@ resolution y = 600 fullscreen = false screen = 0 +# Minimize the window if it loses key focus? +minimize on focus loss = true + # Render system # blank means default # Valid values: @@ -137,9 +140,7 @@ refraction = true rtt size = 512 reflect terrain = true reflect statics = false -reflect small statics = false reflect actors = false -reflect misc = false [Sound] # Device name. Blank means default diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c816f2060..5f9578988 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -157,5 +157,6 @@ void OgreRenderer::setFov(float fov) void OgreRenderer::windowResized(int x, int y) { - mWindowListener->windowResized(x,y); + if (mWindowListener) + mWindowListener->windowResized(x,y); }