diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8920c17b41..ed43059f4f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -31,17 +31,74 @@ namespace { static const int invalidWeatherID = -1; + // linear interpolate between x and y based on factor. float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; } - + // linear interpolate between x and y based on factor. osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } } +template +T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings) const +{ + // TODO: use pre/post sunset/sunrise time values in [Weather] section + + // night + if (gameHour <= timeSettings.mNightEnd || gameHour >= timeSettings.mNightStart + 1) + return mNightValue; + // sunrise + else if (gameHour >= timeSettings.mNightEnd && gameHour <= timeSettings.mDayStart + 1) + { + if (gameHour <= timeSettings.mSunriseTime) + { + // fade in + float advance = timeSettings.mSunriseTime - gameHour; + float factor = advance / 0.5f; + return lerp(mSunriseValue, mNightValue, factor); + } + else + { + // fade out + float advance = gameHour - timeSettings.mSunriseTime; + float factor = advance / 3.f; + return lerp(mSunriseValue, mDayValue, factor); + } + } + // day + else if (gameHour >= timeSettings.mDayStart + 1 && gameHour <= timeSettings.mDayEnd - 1) + return mDayValue; + // sunset + else if (gameHour >= timeSettings.mDayEnd - 1 && gameHour <= timeSettings.mNightStart + 1) + { + if (gameHour <= timeSettings.mDayEnd + 1) + { + // fade in + float advance = (timeSettings.mDayEnd + 1) - gameHour; + float factor = (advance / 2); + return lerp(mSunsetValue, mDayValue, factor); + } + else + { + // fade out + float advance = gameHour - (timeSettings.mDayEnd + 1); + float factor = advance / 2.f; + return lerp(mSunsetValue, mNightValue, factor); + } + } + // shut up compiler + return T(); +} + + + +template class TimeOfDayInterpolator; +template class TimeOfDayInterpolator; + Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, @@ -49,22 +106,22 @@ Weather::Weather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) - , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) - , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) - , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) - , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) - , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) - , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) - , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) - , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) - , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) - , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) - , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) - , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) - , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) - , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) - , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) - , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) @@ -432,16 +489,13 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) - , mNightStart(mSunsetTime + mSunsetDuration) - , mNightEnd(mSunriseTime - 0.5f) - , mDayStart(mSunriseTime + mSunriseDuration) - , mDayEnd(mSunsetTime) + , mNightFade(0, 0, 0, 1) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) - , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) - , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) - , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) - , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) + , mUnderwaterFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog"), + fallback.getFallbackFloat("Water_UnderwaterDayFog"), + fallback.getFallbackFloat("Water_UnderwaterSunsetFog"), + fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -461,6 +515,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mAmbientSound() , mPlayingSoundID() { + mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; + mTimeSettings.mNightEnd = mSunriseTime - 0.5f; + mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration; + mTimeSettings.mDayEnd = mSunsetTime; + mTimeSettings.mSunriseTime = mSunriseTime; + mWeatherSettings.reserve(10); addWeather("Clear", fallback); // 0 addWeather("Cloudy", fallback); // 1 @@ -593,7 +653,7 @@ void WeatherManager::update(float duration, bool paused) } // disable sun during night - if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); else mRendering.getSkyManager()->sunEnable(); @@ -604,10 +664,10 @@ void WeatherManager::update(float duration, bool paused) { // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = time.getHour(); - float adjustedNightStart = mNightStart; + float adjustedNightStart = mTimeSettings.mNightStart; if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; - if ( mNightStart < mSunriseTime ) + if ( mTimeSettings.mNightStart < mSunriseTime ) adjustedNightStart += 24.f; const bool is_night = adjustedHour >= adjustedNightStart; @@ -628,52 +688,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() - float gameHour = time.getHour(); - float underwaterFog; - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - underwaterFog = mUnderwaterNightFog; - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); - } - } - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - underwaterFog = mUnderwaterDayFog; - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); - } - } + float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) @@ -748,7 +763,7 @@ bool WeatherManager::isDark() const TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1); } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) @@ -1026,81 +1041,15 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - 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 (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - 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 (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - 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 (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - 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; - } - } + mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); + mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); + mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); + mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings); + mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings); if (gameHour >= mSunsetTime - mSunPreSunsetTime) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a1a7d30774..86d1898fa9 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -34,6 +34,33 @@ namespace MWWorld class Fallback; class TimeStamp; + + struct TimeOfDaySettings + { + float mNightStart; + float mNightEnd; + float mDayStart; + float mDayEnd; + float mSunriseTime; + }; + + /// Interpolates between 4 data points (sunrise, day, sunset, night) based on the time of day. + /// The template value could be a floating point number, or a color. + template + class TimeOfDayInterpolator + { + public: + TimeOfDayInterpolator(const T& sunrise, const T& day, const T& sunset, const T& night) + : mSunriseValue(sunrise), mDayValue(day), mSunsetValue(sunset), mNightValue(night) + { + } + + T getValue (const float gameHour, const TimeOfDaySettings& timeSettings) const; + + private: + T mSunriseValue, mDayValue, mSunsetValue, mNightValue; + }; + /// Defines a single weather setting (according to INI) class Weather { @@ -47,29 +74,14 @@ namespace MWWorld std::string mCloudTexture; - // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor; - osg::Vec4f mSkyDayColor; - osg::Vec4f mSkySunsetColor; - osg::Vec4f mSkyNightColor; - - // Fog colors - osg::Vec4f mFogSunriseColor; - osg::Vec4f mFogDayColor; - osg::Vec4f mFogSunsetColor; - osg::Vec4f mFogNightColor; - - // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor; - osg::Vec4f mAmbientDayColor; - osg::Vec4f mAmbientSunsetColor; - osg::Vec4f mAmbientNightColor; - - // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor; - osg::Vec4f mSunDayColor; - osg::Vec4f mSunSunsetColor; - osg::Vec4f mSunNightColor; + // Sky (atmosphere) color + TimeOfDayInterpolator mSkyColor; + // Fog color + TimeOfDayInterpolator mFogColor; + // Ambient lighting color + TimeOfDayInterpolator mAmbientColor; + // Sun (directional) lighting color + TimeOfDayInterpolator mSunColor; // Fog depth/density float mLandFogDayDepth; @@ -243,18 +255,17 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mSunPreSunsetTime; - float mNightStart; - float mNightEnd; - float mDayStart; - float mDayEnd; + + TimeOfDaySettings mTimeSettings; + + // fading of night skydome + TimeOfDayInterpolator mNightFade; + float mHoursBetweenWeatherChanges; float mRainSpeed; // underwater fog not really related to weather, but we handle it here because it's convenient - float mUnderwaterSunriseFog; - float mUnderwaterDayFog; - float mUnderwaterSunsetFog; - float mUnderwaterNightFog; + TimeOfDayInterpolator mUnderwaterFog; std::vector mWeatherSettings; MoonModel mMasser;