diff --git a/rwengine/src/data/Weather.cpp b/rwengine/src/data/Weather.cpp index b59e017d..cba93dcf 100644 --- a/rwengine/src/data/Weather.cpp +++ b/rwengine/src/data/Weather.cpp @@ -1,34 +1,59 @@ #include "Weather.hpp" -#define MIXPROP(prop) data.prop = glm::mix(x.prop, y.prop, a) -Weather::Entry Weather::getWeatherData(WeatherCondition cond, float tod) { - const auto i = size_t(cond) * 24; - RW_ASSERT(i < entries.size()); - - size_t hour = std::floor(tod); - const auto& x = entries[i + hour]; - const auto& y = entries[i + (hour + 1) % 24]; - const float a = tod - std::floor(tod); - - Entry data; - MIXPROP(ambientColor); - MIXPROP(directLightColor); - MIXPROP(skyTopColor); - MIXPROP(skyBottomColor); - MIXPROP(sunCoreColor); - MIXPROP(sunCoreSize); - MIXPROP(sunCoronaSize); - MIXPROP(sunBrightness); - MIXPROP(shadowIntensity); - MIXPROP(lightShading); - MIXPROP(poleShading); - MIXPROP(farClipping); - MIXPROP(fogStart); - MIXPROP(amountGroundLight); - MIXPROP(lowCloudColor); - MIXPROP(topCloudColor); - MIXPROP(bottomCloudColor); - - return data; +namespace { +Weather::Entry interpolateWeather(const Weather::Entry& a, + const Weather::Entry& b, + float t) { +#define MIXPROP(prop) glm::mix(a.prop, b.prop, t) + return { + MIXPROP(ambientColor), + MIXPROP(directLightColor), + MIXPROP(skyTopColor), + MIXPROP(skyBottomColor), + MIXPROP(sunCoreColor), + MIXPROP(sunCoronaColor), + MIXPROP(sunCoreSize), + MIXPROP(sunCoronaSize), + MIXPROP(sunBrightness), + MIXPROP(shadowIntensity), + MIXPROP(lightShading), + MIXPROP(poleShading), + MIXPROP(farClipping), + MIXPROP(fogStart), + MIXPROP(amountGroundLight), + MIXPROP(lowCloudColor), + MIXPROP(topCloudColor), + MIXPROP(bottomCloudColor), + {} + }; +#undef MIXPROP +} +} + +Weather::Entry Weather::interpolate(WeatherCondition prev, + WeatherCondition next, + float a, float tod) { + const float t = tod - std::floor(tod); + const auto nI = size_t(next) * 24; + const auto pI = size_t(prev) * 24; + const auto hour = size_t(tod); + + RW_ASSERT(nI < entries.size()); + const auto& x = entries[nI + hour]; + const auto& y = entries[nI + (hour + 1) % 24]; + + const auto& nextWeather = interpolateWeather(x, y, t); + + if (a >= 1.0f) { + return nextWeather; + } + + RW_ASSERT(pI < entries.size()); + const auto& z = entries[pI + hour]; + const auto& w = entries[pI + (hour + 1) % 24]; + + const auto& prevWeather = interpolateWeather(z, w, t); + + return interpolateWeather(prevWeather, nextWeather, a); } diff --git a/rwengine/src/data/Weather.hpp b/rwengine/src/data/Weather.hpp index 1f866c8f..a5895d67 100644 --- a/rwengine/src/data/Weather.hpp +++ b/rwengine/src/data/Weather.hpp @@ -34,14 +34,9 @@ public: uint8_t unknown[4]; }; - /** - * @brief getWeatherData returns interpolated Weather data for the time of - * day. - * @param cond weather condition - * @param tod float time of day - * @return Correctly interpolated values. - */ - Entry getWeatherData(WeatherCondition condition, float tod); + Entry interpolate(WeatherCondition lastWeather, + WeatherCondition nextWeather, + float a, float tod); std::vector entries; }; diff --git a/rwengine/src/engine/GameState.cpp b/rwengine/src/engine/GameState.cpp index 1fc0fc90..dd02330d 100644 --- a/rwengine/src/engine/GameState.cpp +++ b/rwengine/src/engine/GameState.cpp @@ -21,7 +21,7 @@ BasicState::BasicState() , lastWeather{0} , nextWeather{0} , forcedWeather{0} - , weatherInterpolation{0} + , weatherInterpolation{1.0} , weatherType{0} , cameraData{0} , cameraData2{0} { diff --git a/rwengine/src/render/GameRenderer.cpp b/rwengine/src/render/GameRenderer.cpp index f4dc11af..0ee349ee 100644 --- a/rwengine/src/render/GameRenderer.cpp +++ b/rwengine/src/render/GameRenderer.cpp @@ -243,10 +243,11 @@ void GameRenderer::renderWorld(GameWorld* world, const ViewCamera& camera, const auto currentWeather = WeatherCondition(state->basic.nextWeather); const auto lastWeather = WeatherCondition(state->basic.lastWeather); - /// @todo Interpolate when weatherInterpolation is < 1 - RW_UNUSED(lastWeather); - - auto weather = world->data->weather.getWeatherData(currentWeather, tod); + const auto weatherTransition = state->basic.weatherInterpolation; + auto weather = world->data->weather.interpolate(lastWeather, + currentWeather, + weatherTransition, + tod); float theta = (tod / (60.f * 24.f) - 0.5f) * 2.f * glm::pi(); glm::vec3 sunDirection{