diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 0c93474da9..bff26b63c8 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -90,6 +90,7 @@ target_link_libraries(omwlauncher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${SDL2_LIBRARY} ${QT_LIBRARIES} components ) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 700ba3db9c..615b389d22 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -35,13 +36,14 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g setupUi(this); // Set the maximum res we can set in windowed mode - QRect res = QApplication::desktop()->screenGeometry(); + QRect res = getMaximumResolution(); customWidthSpinBox->setMaximum(res.width()); customHeightSpinBox->setMaximum(res.height()); connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); + connect(screenComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(screenChanged(const QString&))); } @@ -144,17 +146,97 @@ bool GraphicsPage::setupOgre() } antiAliasingComboBox->clear(); - resolutionComboBox->clear(); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); - // Load the rest of the values - loadSettings(); return true; } -void GraphicsPage::loadSettings() +bool GraphicsPage::setupSDL() { + // FIXME: do setupSDLWordaround here instead. + // seems like Qt, SDL and Ogre don't like each other + // results in a segfault if SDL is initialized after Qt + + QStringList screens; + for (int i = 0; i < mScreenCount; i++) + { + screens.append(QString("Screen ") + QString::number(i + 1)); + } + screenComboBox->addItems(screens); + + return true; +} + +std::vector GraphicsPage::mVideoModes; +int GraphicsPage::mScreenCount; + +bool GraphicsPage::setupSDLWordaround() { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + std::cout << "SDL_Init failed: " << SDL_GetError() << std::endl; + return false; + } + + SDL_DisplayMode mode; + int displayIndex, modeIndex, displays = SDL_GetNumVideoDisplays(); + mScreenCount = displays; + + if(displays < 0) + { + std::cout << "SDL_GetNumVideoDisplays failed: " << SDL_GetError() << std::endl; + SDL_Quit(); + return false; + } + + for (displayIndex = 0; displayIndex < displays; displayIndex++) + { + int modes = SDL_GetNumDisplayModes(displayIndex); + if(modes < 0) + { + std::cout << "SDL_GetNumDisplayModes failed: " << SDL_GetError() << std::endl; + SDL_Quit(); + return false; + } + for (modeIndex = 0; modeIndex < modes; modeIndex++) + { + if (SDL_GetDisplayMode(displayIndex, modeIndex, &mode) < 0) + { + std::cout << "SDL_GetDisplayMode failed: " << SDL_GetError() << std::endl; + SDL_Quit(); + return false; + } + + bool isDouble = false; + for (std::vector::iterator it = mVideoModes.begin(); it != mVideoModes.end(); it++) + { + if ((*it).w == mode.w && (*it).h == mode.h && (*it).screen == displayIndex) + { + isDouble = true; + break; + } + } + if (isDouble) + continue; + + VideoMode vmode; + vmode.w = mode.w; + vmode.h = mode.h; + vmode.screen = displayIndex; + mVideoModes.push_back(vmode); + } + } + + SDL_Quit(); + return true; +} + +bool GraphicsPage::loadSettings() +{ + if (!setupSDL()) + return false; + if (!setupOgre()) + return false; + if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -168,6 +250,11 @@ void GraphicsPage::loadSettings() QString width = mGraphicsSettings.value(QString("Video/resolution x")); QString height = mGraphicsSettings.value(QString("Video/resolution y")); QString resolution = width + QString(" x ") + height; + QString screen = mGraphicsSettings.value(QString("Video/screen")); + + int screenIndex = screenComboBox->findText(QString("Screen ") + screen); + if (screenIndex != -1) + screenComboBox->setCurrentIndex(screenIndex); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -180,6 +267,8 @@ void GraphicsPage::loadSettings() customHeightSpinBox->setValue(height.toInt()); } + + return true; } void GraphicsPage::saveSettings() @@ -205,6 +294,11 @@ void GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); } + + QRegExp screenRe(QString(".*(\\d+)")); + if(screenRe.exactMatch(screenComboBox->currentText())) { + mGraphicsSettings.setValue(QString("Video/screen"), screenRe.cap(1)); + } } QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) @@ -240,64 +334,61 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy return result; } -QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) +QStringList GraphicsPage::getAvailableResolutions(int screen) { - QString key("Video Mode"); QStringList result; - - uint row = 0; - Ogre::ConfigOptionMap options = renderer->getConfigOptions(); - - for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) + for (std::vector::iterator it = mVideoModes.begin(); it != mVideoModes.end(); it++) { - if (key.toStdString() != i->first) + VideoMode mode = *it; + if(mode.screen != screen) continue; - Ogre::StringVector::iterator opt_it; - uint idx = 0; + QString aspect = getAspect(mode.w, mode.h); + QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h); - for (opt_it = i->second.possibleValues.begin (); - opt_it != i->second.possibleValues.end (); opt_it++, idx++) - { - QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - QString resolution = QString::fromStdString(*opt_it).simplified(); + if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { + resolution.append(tr("\t(Wide ") + aspect + ")"); - if (resolutionRe.exactMatch(resolution)) { - - int width = resolutionRe.cap(1).toInt(); - int height = resolutionRe.cap(2).toInt(); - - QString aspect = getAspect(width, height); - QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2); - - if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - cleanRes.append(tr("\t(Wide ") + aspect + ")"); - - } else if (aspect == QLatin1String("4:3")) { - cleanRes.append(tr("\t(Standard 4:3)")); - } - // do not add duplicate resolutions - if (!result.contains(cleanRes)) - result.append(cleanRes); - } + } else if (aspect == QLatin1String("4:3")) { + resolution.append(tr("\t(Standard 4:3)")); } + + result.append(resolution); } - - // Sort the resolutions in descending order - qSort(result.begin(), result.end(), naturalSortGreaterThanCI); - return result; } +QRect GraphicsPage::getMaximumResolution() +{ + QRect max; + int screens = QApplication::desktop()->screenCount(); + for (int i = 0; i < screens; ++i) + { + QRect res = QApplication::desktop()->screenGeometry(i); + if (res.width() > max.width()) + max.setWidth(res.width()); + if (res.height() > max.height()) + max.setHeight(res.height()); + } + return max; +} + void GraphicsPage::rendererChanged(const QString &renderer) { mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); antiAliasingComboBox->clear(); - resolutionComboBox->clear(); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); +} + +void GraphicsPage::screenChanged(const QString &screen) +{ + QRegExp screenRe(QString(".*(\\d+)")); + if(screenRe.exactMatch(screen)) { + resolutionComboBox->clear(); + resolutionComboBox->addItems(getAvailableResolutions(screenRe.cap(1).toInt() - 1)); + } } void GraphicsPage::slotFullScreenChanged(int state) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 21039af430..5ed4e5632e 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -18,6 +18,13 @@ #include "ui_graphicspage.h" +struct VideoMode +{ + int w; + int h; + int screen; +}; + class GraphicsSettings; namespace Files { struct ConfigurationManager; } @@ -30,10 +37,14 @@ public: GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); void saveSettings(); - bool setupOgre(); + bool loadSettings(); + + // SDL workaround + static bool setupSDLWordaround(); public slots: void rendererChanged(const QString &renderer); + void screenChanged(const QString &screen); private slots: void slotFullScreenChanged(int state); @@ -55,10 +66,14 @@ private: GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); - QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); + QStringList getAvailableResolutions(int screen); + QRect getMaximumResolution(); - void loadSettings(); + static std::vector mVideoModes; + static int mScreenCount; + bool setupOgre(); + bool setupSDL(); }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 09da1d615f..e444bb9f2b 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -3,9 +3,14 @@ #include #include "maindialog.hpp" +// SDL workaround +#include "graphicspage.hpp" int main(int argc, char *argv[]) { + // SDL woraround + GraphicsPage::setupSDLWordaround(); + QApplication app(argc, argv); // Now we make sure the current dir is set to application path diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 10a3f015a3..b75d09c51c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -292,8 +292,8 @@ bool MainDialog::setup() // Now create the pages as they need the settings createPages(); - // Call this so we can exit on Ogre errors before mainwindow is shown - if (!mGraphicsPage->setupOgre()) + // Call this so we can exit on Ogre/SDL errors before mainwindow is shown + if (!mGraphicsPage->loadSettings()) return false; loadSettings(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 8a57234b8f..c9a7806918 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -224,16 +225,22 @@ namespace MWGui void Choice::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.0, 1.0); MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); } void Topic::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); } void Goodbye::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aec00a8c6d..22facdcaf0 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME #include "../mwbase/soundmanager.hpp" @@ -353,7 +355,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -422,6 +424,7 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; + MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); MWBase::Environment::get().getWindowManager ()->loadingDone (); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8b3c5f6ffa..10dbdae9bb 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,8 +1,5 @@ #include "weather.hpp" -#include -#include - #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -91,10 +88,11 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang } WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), - mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), - mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering) + mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), + mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), + mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), + mMonth(0), mDay(0), mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), + mRendering(rendering) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -197,32 +195,31 @@ void WeatherManager::setWeather(const String& weather, bool instant) mFirstUpdate = false; } -WeatherResult WeatherManager::getResult(const String& weather) +void WeatherManager::setResult(const String& weatherType) { - const Weather& current = mWeatherSettings[weather]; - WeatherResult result; + const Weather& current = mWeatherSettings[weatherType]; - result.mCloudTexture = current.mCloudTexture; - result.mCloudBlendFactor = 0; - result.mCloudOpacity = current.mCloudsMaximumPercent; - result.mWindSpeed = current.mWindSpeed; - result.mCloudSpeed = current.mCloudSpeed; - result.mGlareView = current.mGlareView; - result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - result.mSunColor = current.mSunDiscSunsetColor; - - result.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); + mResult.mCloudTexture = current.mCloudTexture; + mResult.mCloudBlendFactor = 0; + mResult.mCloudOpacity = current.mCloudsMaximumPercent; + mResult.mWindSpeed = current.mWindSpeed; + mResult.mCloudSpeed = current.mCloudSpeed; + mResult.mGlareView = current.mGlareView; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mSunColor = current.mSunDiscSunsetColor; - result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); + + mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; // night if (mHour <= mNightEnd || mHour >= mNightStart + 1) { - result.mFogColor = current.mFogNightColor; - result.mAmbientColor = current.mAmbientNightColor; - result.mSunColor = current.mSunNightColor; - result.mSkyColor = current.mSkyNightColor; - result.mNightFade = 1.f; + mResult.mFogColor = current.mFogNightColor; + mResult.mAmbientColor = current.mAmbientNightColor; + mResult.mSunColor = current.mSunNightColor; + mResult.mSkyColor = current.mSkyNightColor; + mResult.mNightFade = 1.f; } // sunrise @@ -233,31 +230,31 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = mSunriseTime - mHour; float factor = advance / 0.5f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - result.mNightFade = factor; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; } else //if (mHour >= 6) { // fade out float advance = mHour - mSunriseTime; float factor = advance / 3.f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); } } // day else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1) { - result.mFogColor = current.mFogDayColor; - result.mAmbientColor = current.mAmbientDayColor; - result.mSunColor = current.mSunDayColor; - result.mSkyColor = current.mSkyDayColor; + mResult.mFogColor = current.mFogDayColor; + mResult.mAmbientColor = current.mAmbientDayColor; + mResult.mSunColor = current.mSunDayColor; + mResult.mSkyColor = current.mSkyDayColor; } // sunset @@ -268,54 +265,51 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = (mDayEnd + 1) - mHour; float factor = (advance / 2); - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); } else //if (mHour >= 19) { // fade out float advance = mHour - (mDayEnd + 1); float factor = advance / 2.f; - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - result.mNightFade = factor; + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; } } - - return result; } -WeatherResult WeatherManager::transition(float factor) +void WeatherManager::transition(float factor) { - const WeatherResult& current = getResult(mCurrentWeather); - const WeatherResult& other = getResult(mNextWeather); - WeatherResult result; + setResult(mCurrentWeather); + const WeatherResult current = mResult; + setResult(mNextWeather); + const WeatherResult other = mResult; - result.mCloudTexture = current.mCloudTexture; - result.mNextCloudTexture = other.mCloudTexture; - result.mCloudBlendFactor = factor; + mResult.mCloudTexture = current.mCloudTexture; + mResult.mNextCloudTexture = other.mCloudTexture; + mResult.mCloudBlendFactor = factor; - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); - result.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); - result.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); - result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); + mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); - result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); - result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); - result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); - result.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); - result.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); + mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); - result.mNight = current.mNight; - - return result; + mResult.mNight = current.mNight; } void WeatherManager::update(float duration) @@ -325,263 +319,227 @@ void WeatherManager::update(float duration) mWeatherUpdateTime -= timePassed; - bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - - if (exterior) - { - std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - - std::string weather = "clear"; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - weather = mRegionOverrides[regionstr]; - else - { - // get weather probabilities for the current region - const ESM::Region *region = - MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); - - if (region != 0) - { - float clear = region->mData.mClear/255.f; - float cloudy = region->mData.mCloudy/255.f; - float foggy = region->mData.mFoggy/255.f; - float overcast = region->mData.mOvercast/255.f; - float rain = region->mData.mRain/255.f; - float thunder = region->mData.mThunder/255.f; - float ash = region->mData.mAsh/255.f; - float blight = region->mData.mBlight/255.f; - float snow = region->mData.mA/255.f; - float blizzard = region->mData.mB/255.f; - - // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; - - float random = ((rand()%100)/100.f) * total; - - if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blizzard"; - else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "snow"; - else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blight"; - else if (random >= thunder+rain+overcast+foggy+cloudy+clear) - weather = "ashstorm"; - else if (random >= rain+overcast+foggy+cloudy+clear) - weather = "thunderstorm"; - else if (random >= overcast+foggy+cloudy+clear) - weather = "rain"; - else if (random >= foggy+cloudy+clear) - weather = "overcast"; - else if (random >= cloudy+clear) - weather = "foggy"; - else if (random >= clear) - weather = "cloudy"; - else - weather = "clear"; - } - } - - setWeather(weather, false); - } - - WeatherResult result; - - if (mNextWeather != "") - { - mRemainingTransitionTime -= timePassed; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - result = transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); - else - result = getResult(mCurrentWeather); - - mWindSpeed = result.mWindSpeed; - - mRendering->configureFog(result.mFogDepth, result.mFogColor); - - // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); - else - mRendering->getSkyManager()->sunEnable(); - - // sun angle - float height; - - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; - - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); - - int facing = (mHour > 13.f) ? 1 : -1; - - Vector3 final( - -(1 - height) * facing, - -(1 - height) * facing, - height); - mRendering->setSunDirection(final); - - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - Vector3 masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - Vector3 secunda( - (moonHeight - 1) * facing * 1.25, - (1 - moonHeight) * facing * 0.8, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } - - if (mCurrentWeather == "thunderstorm" && mNextWeather == "" && exterior) - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = rand() % 4; - std::string soundname; - if (sound == 0) soundname = mThunderSoundID0; - else if (sound == 1) soundname = mThunderSoundID1; - else if (sound == 2) soundname = mThunderSoundID2; - else if (sound == 3) soundname = mThunderSoundID3; - MWBase::Environment::get().getSoundManager()->playSound(soundname, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - else - { - srand(time(NULL)); - mThunderChanceNeeded = rand() % 100; - mThunderChance = 0; - mRendering->getSkyManager()->setLightningStrength( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = mThunderThreshold; - - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - - mThunderSoundDelay = 0.25; - } - } - } - else - mRendering->getSkyManager()->setLightningStrength(0.f); - - mRendering->setAmbientColour(result.mAmbientColor); - mRendering->sunEnable(false); - mRendering->setSunColour(result.mSunColor); - - mRendering->getSkyManager()->setWeather(result); - } - else + const bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + if (!exterior) { mRendering->sunDisable(false); mRendering->skyDisable(); mRendering->getSkyManager()->setLightningStrength(0.f); + stopSounds(true); + return; } - // play sounds - std::string ambientSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID : ""); - if (!exterior) ambientSnd = ""; - if (ambientSnd != "") + // Exterior + std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); + + if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { - if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) + mCurrentRegion = regionstr; + mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; + + std::string weatherType = "clear"; + + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) + weatherType = mRegionOverrides[regionstr]; + else + { + // get weather probabilities for the current region + const ESM::Region *region = + MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); + + if (region != 0) + { + weatherType = nextWeather(region); + } + } + + setWeather(weatherType, false); + } + + if (mNextWeather != "") + { + mRemainingTransitionTime -= timePassed; + if (mRemainingTransitionTime < 0) + { + mCurrentWeather = mNextWeather; + mNextWeather = ""; + } + } + + if (mNextWeather != "") + transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); + else + setResult(mCurrentWeather); + + mWindSpeed = mResult.mWindSpeed; + + mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); + + // disable sun during night + if (mHour >= mNightStart || mHour <= mSunriseTime) + mRendering->getSkyManager()->sunDisable(); + else + mRendering->getSkyManager()->sunEnable(); + + // sun angle + float height; + + //Day duration + float dayDuration = (mNightStart - 1) - mSunriseTime; + + // rise at 6, set at 20 + if (mHour >= mSunriseTime && mHour <= mNightStart) + height = 1 - std::abs(((mHour - dayDuration) / 7.f)); + else if (mHour > mNightStart) + height = (mHour - mNightStart) / 4.f; + else //if (mHour > 0 && mHour < 6) + height = 1 - (mHour / mSunriseTime); + + int facing = (mHour > 13.f) ? 1 : -1; + + Vector3 final( + (height - 1) * facing, + (height - 1) * facing, + height); + mRendering->setSunDirection(final); + + /* + * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish + * for masser and secunda + */ + + float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); + float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); + + //moon calculations + float moonHeight; + if (mHour >= fadeInStart) + moonHeight = mHour - fadeInStart; + else if (mHour <= fadeOutFinish) + moonHeight = mHour + fadeOutFinish; + else + moonHeight = 0; + + moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); + + if (moonHeight != 0) + { + int facing = (moonHeight <= 1) ? 1 : -1; + Vector3 masser( + (moonHeight - 1) * facing, + (1 - moonHeight) * facing, + moonHeight); + + Vector3 secunda( + (moonHeight - 1) * facing * 1.25, + (1 - moonHeight) * facing * 0.8, + moonHeight); + + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); + + float angle = (1-moonHeight) * 90.f * facing; + float masserHourFade = calculateHourFade("Masser"); + float secundaHourFade = calculateHourFade("Secunda"); + float masserAngleFade = calculateAngleFade("Masser", angle); + float secundaAngleFade = calculateAngleFade("Secunda", angle); + + masserAngleFade *= masserHourFade; + secundaAngleFade *= secundaHourFade; + + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + } + else + { + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); + } + + if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + { + if (mThunderFlash > 0) + { + // play the sound after a delay + mThunderSoundDelay -= duration; + if (mThunderSoundDelay <= 0) + { + // pick a random sound + int sound = rand() % 4; + std::string* soundName; + if (sound == 0) soundName = &mThunderSoundID0; + else if (sound == 1) soundName = &mThunderSoundID1; + else if (sound == 2) soundName = &mThunderSoundID2; + else if (sound == 3) soundName = &mThunderSoundID3; + MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0); + mThunderSoundDelay = 1000; + } + + mThunderFlash -= duration; + if (mThunderFlash > 0) + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + else + { + mThunderChanceNeeded = rand() % 100; + mThunderChance = 0; + mRendering->getSkyManager()->setLightningStrength( 0.f ); + } + } + else + { + // no thunder active + mThunderChance += duration*4; // chance increases by 4 percent every second + if (mThunderChance >= mThunderChanceNeeded) + { + mThunderFlash = mThunderThreshold; + + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + + mThunderSoundDelay = 0.25; + } + } + } + else + mRendering->getSkyManager()->setLightningStrength(0.f); + + mRendering->setAmbientColour(mResult.mAmbientColor); + mRendering->sunEnable(false); + mRendering->setSunColour(mResult.mSunColor); + + mRendering->getSkyManager()->setWeather(mResult); + + + // Play sounds + if (mNextWeather == "") + { + std::string ambientSnd = mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID; + if (!ambientSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(ambientSnd); MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } - } - std::string rainSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mRainLoopSoundID : ""); - if (!exterior) rainSnd = ""; - if (rainSnd != "") - { - if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) + std::string rainSnd = mWeatherSettings[mCurrentWeather].mRainLoopSoundID; + if (!rainSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(rainSnd); MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } } - // stop sounds - std::vector::iterator it=mSoundsPlaying.begin(); + stopSounds(false); +} + +void WeatherManager::stopSounds(bool stopAll) +{ + std::vector::iterator it = mSoundsPlaying.begin(); while (it!=mSoundsPlaying.end()) { - if ( *it != ambientSnd && *it != rainSnd) + if (stopAll || \ + !((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) || \ + (*it == mWeatherSettings[mCurrentWeather].mRainLoopSoundID))) { MWBase::Environment::get().getSoundManager()->stopSound(*it); it = mSoundsPlaying.erase(it); @@ -591,6 +549,61 @@ void WeatherManager::update(float duration) } } +Ogre::String WeatherManager::nextWeather(const ESM::Region* region) const +{ + /* + * All probabilities must add to 100 (responsibility of the user). + * If chances A and B has values 30 and 70 then by generating + * 100 numbers 1..100, 30% will be lesser or equal 30 and + * 70% will be greater than 30 (in theory). + */ + const int probability[] = { + region->mData.mClear, + region->mData.mCloudy, + region->mData.mFoggy, + region->mData.mOvercast, + region->mData.mRain, + region->mData.mThunder, + region->mData.mAsh, + region->mData.mBlight, + region->mData.mA, + region->mData.mB + }; // 10 elements + + int chance = (rand() % 100) + 1; // 1..100 + int sum = 0; + for (int i = 0; i < 10; ++i) + { + sum += probability[i]; + if (chance < sum) + { + switch (i) + { + case 1: + return "cloudy"; + case 2: + return "foggy"; + case 3: + return "overcast"; + case 4: + return "rain"; + case 5: + return "thunderstorm"; + case 6: + return "ashstorm"; + case 7: + return "blight"; + case 8: + return "snow"; + case 9: + return "blizzard"; + default: // case 0 + return "clear"; + } + } + } +} + void WeatherManager::setHour(const float hour) { mHour = hour; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 081bd7f87d..1a787aae8f 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -4,6 +4,11 @@ #include #include +namespace ESM +{ + struct Region; +} + namespace MWRender { class RenderingManager; @@ -129,6 +134,8 @@ namespace MWWorld */ void update(float duration); + void stopSounds(bool stopAll); + void setHour(const float hour); float getWindSpeed() const; @@ -171,13 +178,16 @@ namespace MWWorld double mTimePassed; // time passed since last update - WeatherResult transition(const float factor); - WeatherResult getResult(const Ogre::String& weather); + void transition(const float factor); + void setResult(const Ogre::String& weatherType); float calculateHourFade (const std::string& moonName) const; float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const Ogre::String& weather, bool instant=false); + void setWeather(const Ogre::String& weatherType, bool instant=false); + Ogre::String nextWeather(const ESM::Region* region) const; + WeatherResult mResult; + float mSunriseTime; float mSunsetTime; float mSunriseDuration; diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index 5c330cebd5..7e9fe00d9e 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -58,6 +58,13 @@ + + + Screen: + + + + Resolution: @@ -71,6 +78,9 @@ + + +