From 0d5df7bc52f02ec274798c128e0e8c2537241fa2 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Apr 2025 18:40:54 -0600 Subject: [PATCH 01/15] Rewrite moon logic to match vanilla's phase and visibility times --- apps/openmw/mwworld/weather.cpp | 167 +++++++++++++++++++++++++------- apps/openmw/mwworld/weather.hpp | 11 ++- 2 files changed, 142 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4f6f52a81a..c51ec4b574 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -352,6 +352,27 @@ namespace MWWorld mWeather = 0; } + MoonModel::MoonModel(const std::string& name, float fadeInStart, float fadeInFinish, float fadeOutStart, + float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, + float fadeEndAngle, float moonShadowEarlyFadeAngle) + { + mName = name; + mFadeInStart = fadeInStart; + mFadeInFinish = fadeInFinish; + mFadeOutStart = fadeOutStart; + mFadeOutFinish = fadeOutFinish; + mAxisOffset = axisOffset; + mDailyIncrement = dailyIncrement; + mFadeStartAngle = fadeStartAngle; + mFadeEndAngle = fadeEndAngle; + mMoonShadowEarlyFadeAngle = moonShadowEarlyFadeAngle; + + // Morrowind appears to have a minimum speed to avoid situations where the moon can't + // complete a full rotation in a single 24-hour period. The reverse-engineered formula is + // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). + mSpeed = std::max(speed, (180.0f / 23.0f / 15.0f)); + } + MoonModel::MoonModel(const std::string& name) : mFadeInStart(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Start")) , mFadeInFinish(Fallback::Map::getFloat("Moons_" + name + "_Fade_In_Finish")) @@ -364,14 +385,17 @@ namespace MWWorld , mFadeEndAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_End_Angle")) , mMoonShadowEarlyFadeAngle(Fallback::Map::getFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) { - // Morrowind appears to have a minimum speed in order to avoid situations where the moon couldn't conceivably - // complete a rotation in a single 24 hour period. The value of 180/23 was deduced from reverse engineering. - mSpeed = std::min(mSpeed, 180.0f / 23.0f); + mName = name; + + // Morrowind appears to have a minimum speed to avoid situations where the moon can't + // complete a full rotation in a single 24-hour period. The reverse-engineered formula is + // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). + mSpeed = std::max(mSpeed, (180.0f / 23.0f / 15.0f)); } MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const { - float rotationFromHorizon = angle(gameTime); + float rotationFromHorizon = angle(gameTime.getDay(), gameTime.getHour()); MWRender::MoonState state = { rotationFromHorizon, mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. phase(gameTime), shadowBlend(rotationFromHorizon), @@ -380,7 +404,7 @@ namespace MWWorld return state; } - inline float MoonModel::angle(const TimeStamp& gameTime) const + inline float MoonModel::angle(int gameDay, float gameHour) const { // Morrowind's moons start travel on one side of the horizon (let's call it H-rise) and travel 180 degrees to // the opposite horizon (let's call it H-set). Upon reaching H-set, they reset to H-rise until the next moon @@ -390,49 +414,92 @@ namespace MWWorld // 1. Moon rises and then sets in one day. // 2. Moon sets and doesn't rise in one day (occurs when the moon rise hour is >= 24). // 3. Moon sets and then rises in one day. - float moonRiseHourToday = moonRiseHour(gameTime.getDay()); - float moonRiseAngleToday = 0; + float moonRiseHourToday = moonRiseHour(gameDay); + float moonRiseAngleToday = 0.0f; - if (gameTime.getHour() < moonRiseHourToday) + if (gameHour < moonRiseHourToday) { - float moonRiseHourYesterday = moonRiseHour(gameTime.getDay() - 1); - if (moonRiseHourYesterday < 24) + // Rise hour increases by mDailyIncrement each day, so yesterday's is easy to calculate + float moonRiseHourYesterday = moonRiseHourToday - mDailyIncrement; + if (moonRiseHourYesterday < 24.0f) { - float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); - if (moonRiseAngleYesterday < 180) + // Morrowind offsets the increment by -1 when the previous day's visible point crosses into the next day. + // The offset lasts from this point until the next 24-day loop starts. + // To find this point we add mDailyIncrement to the previous visible point and check the result. + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float timeToVisible = moonShadowEarlyFadeAngle1 / rotation(1.0f); + float cycleOffset = (((moonRiseHourToday >= 24.0f) || (moonRiseHourYesterday + timeToVisible > 24.0f)) + ? mDailyIncrement + : 0.0f); + + float moonRiseAngleYesterday = rotation(24.0f - (moonRiseHourYesterday + cycleOffset)); + if (moonRiseAngleYesterday < 180.0f) { // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've // travelled today. - moonRiseAngleToday = rotation(gameTime.getHour()) + moonRiseAngleYesterday; + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; } } } else { - moonRiseAngleToday = rotation(gameTime.getHour() - moonRiseHourToday); + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); } - if (moonRiseAngleToday >= 180) + if (moonRiseAngleToday >= 180.0f) { // The moon set today, reset the angle to the horizon. - moonRiseAngleToday = 0; + moonRiseAngleToday = 0.0f; } return moonRiseAngleToday; } - inline float MoonModel::moonRiseHour(unsigned int daysPassed) const + inline float MoonModel::moonPhaseHour(int gameDay) const { - // This arises from the start date of 16 Last Seed, 427 - // TODO: Find an alternate formula that doesn't rely on this day being fixed. - static const unsigned int startDay = 16; + // Morrowind delays moon phase changes until one of these is true: + // * The moon is invisible at midnight. + // * The moon reached moonShadowEarlyFadeAngle2 one daily increment ago (therefore invisible). + if (!isVisible(gameDay, 0.0f)) + return 0.0f; + else + { + // Calculate the angle at which the moon becomes transparent and the starting angle. + float moonShadowEarlyFadeAngle2 = (180.0f - mFadeEndAngle) + mMoonShadowEarlyFadeAngle; + float midnightAngle = angle(gameDay, 0.0f); - // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning - // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. - // Note that we don't modulo after adding the latest daily increment because other calculations need to - // know if doing so would cause the moon rise to be postponed until the next day (which happens when - // the moon rise hour is >= 24 in Morrowind). - return mDailyIncrement + std::fmod((daysPassed - 1 + startDay) * mDailyIncrement, 24.0f); + // We can assume that moonShadowEarlyFadeAngle2 > midnightAngle, because the opposite + // case would make the moon invisible at midnight, which is checked above. + return ((moonShadowEarlyFadeAngle2 - midnightAngle) / rotation(1.0f)) + mDailyIncrement; + } + } + + inline float MoonModel::moonRiseHour(int gameDay) const + { + if (mFadeEndAngle > 0.0f && mFadeEndAngle < 180.0f) + { + // This arises from the start date of 16 Last Seed, 427 + // TODO: Find an alternate formula that doesn't rely on this day being fixed. + static const int startDay = 16; + + // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. + // The offset increases on the first day of the loop and is multiplied by the number of completed loops. + float incrementOffset = (24.0f - (24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); + + // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning + // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. + // Note that we don't modulo after adding the latest daily increment because other calculations need to + // know if doing so would cause the moon rise to be postponed until the next day (which happens when + // the moon rise hour is >= 24 in Morrowind). + return mDailyIncrement + + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); + } + else + { + // Morrowind uses a fixed rise hour multiplied by daily increment when + // the moon is always visible. + return std::fmod(17.0f * mDailyIncrement, 24.0f); + } } inline float MoonModel::rotation(float hours) const @@ -447,12 +514,40 @@ namespace MWWorld { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day // phase cycle. - - // If the moon didn't rise yet today, use yesterday's moon phase. - if (gameTime.getHour() < moonRiseHour(gameTime.getDay())) - return static_cast((gameTime.getDay() / 3) % 8); + if (mFadeEndAngle > 0.0f && mFadeEndAngle < 180.0f) + { + // If the moon didn't rise yet today, use yesterday's moon phase. + if (gameTime.getHour() < moonPhaseHour(gameTime.getDay())) + return static_cast((gameTime.getDay() / 3) % 8); + else + return static_cast(((gameTime.getDay() + 1) / 3) % 8); + } else - return static_cast(((gameTime.getDay() + 1) / 3) % 8); + { + // The moon is locked to Full when it never goes invisible. + return static_cast(1); + } + } + + inline bool MoonModel::isVisible(int gameDay, float gameHour) const + { + // Morrowind culls the moon one minute before mFadeOutFinish. + static const float oneMinute = 0.0167f; + + // The moon isn't visible from mFadeOutFinish to mFadeInStart. + if ((gameHour >= (mFadeOutFinish - oneMinute)) && (gameHour < mFadeInStart)) + return false; + + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; + + // The moon isn't visible before moonShadowEarlyFadeAngle1 and after moonShadowEarlyFadeAngle2. + float currentAngle = angle(gameDay, gameHour); + if ((currentAngle <= moonShadowEarlyFadeAngle1) || (currentAngle >= moonShadowEarlyFadeAngle2)) + return false; + + return true; } inline float MoonModel::shadowBlend(float angle) const @@ -480,6 +575,10 @@ namespace MWWorld inline float MoonModel::hourlyAlpha(float gameHour) const { + // Morrowind culls the moon one minute before mFadeOutFinish + static const float oneMinute = 0.0167f; + float adjustedFadeOutFinish = mFadeOutFinish - oneMinute; + // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon // appears and disappears. // Depending on the current hour, the following values describe how transparent the moon is. @@ -487,9 +586,9 @@ namespace MWWorld // 2. From Fade Out Finish to Fade In Start: 0 (transparent) // 3. From Fade In Start to Fade In Finish: 0..1 // 4. From Fade In Finish to Fade Out Start: 1 (solid) - if ((gameHour >= mFadeOutStart) && (gameHour < mFadeOutFinish)) - return (mFadeOutFinish - gameHour) / (mFadeOutFinish - mFadeOutStart); - else if ((gameHour >= mFadeOutFinish) && (gameHour < mFadeInStart)) + if ((gameHour >= mFadeOutStart) && (gameHour < adjustedFadeOutFinish)) + return (adjustedFadeOutFinish - gameHour) / (adjustedFadeOutFinish - mFadeOutStart); + else if ((gameHour >= adjustedFadeOutFinish) && (gameHour < mFadeInStart)) return 0.0f; else if ((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 0643240dcd..fe47722f85 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -251,6 +251,10 @@ namespace MWWorld { public: MoonModel(const std::string& name); + MoonModel(const std::string& name, float fadeInStart, + float fadeInFinish, float fadeOutStart, float fadeOutFinish, + float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, + float fadeEndAngle, float moonShadowEarlyFadeAngle); MWRender::MoonState calculateState(const TimeStamp& gameTime) const; @@ -265,11 +269,14 @@ namespace MWWorld float mFadeStartAngle; float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; + std::string mName; - float angle(const TimeStamp& gameTime) const; - float moonRiseHour(unsigned int daysPassed) const; + float angle(int gameDay, float gameHour) const; + float moonPhaseHour(int gameDay) const; + float moonRiseHour(int gameDay) const; float rotation(float hours) const; MWRender::MoonState::Phase phase(const TimeStamp& gameTime) const; + bool isVisible(int gameDay, float gameHour) const; float shadowBlend(float angle) const; float hourlyAlpha(float gameHour) const; float earlyMoonShadowAlpha(float angle) const; From 009a574d087231ac644f20d559609e3d8a4fa47b Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Apr 2025 18:41:22 -0600 Subject: [PATCH 02/15] Add moon logic unit tests --- apps/openmw_tests/CMakeLists.txt | 1 + apps/openmw_tests/mwworld/testweather.cpp | 739 ++++++++++++++++++++++ 2 files changed, 740 insertions(+) create mode 100644 apps/openmw_tests/mwworld/testweather.cpp diff --git a/apps/openmw_tests/CMakeLists.txt b/apps/openmw_tests/CMakeLists.txt index 9b57113110..5cfee9ce4b 100644 --- a/apps/openmw_tests/CMakeLists.txt +++ b/apps/openmw_tests/CMakeLists.txt @@ -10,6 +10,7 @@ file(GLOB UNITTEST_SRC_FILES mwworld/testduration.cpp mwworld/testtimestamp.cpp mwworld/testptr.cpp + mwworld/testweather.cpp mwdialogue/test_keywordsearch.cpp diff --git a/apps/openmw_tests/mwworld/testweather.cpp b/apps/openmw_tests/mwworld/testweather.cpp new file mode 100644 index 0000000000..2f51ad48e1 --- /dev/null +++ b/apps/openmw_tests/mwworld/testweather.cpp @@ -0,0 +1,739 @@ +#include + +#include + +#include "apps/openmw/mwworld/timestamp.hpp" +#include "apps/openmw/mwworld/weather.hpp" + +namespace MWWorld +{ + namespace + { + // MASSER PHASES + + TEST(MWWorldWeatherTest, masserPhasesFullToWaningGibbousAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 2 and 26, 11:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 2 + 11.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 2 + 11.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 26 + 11.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 26 + 11.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(0)); + EXPECT_EQ(afterState.mPhase, static_cast(1)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaningGibbousToThirdQuarterAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 5 and 29, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(1)); + EXPECT_EQ(afterState.mPhase, static_cast(2)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); + } + + TEST(MWWorldWeatherTest, masserPhasesThirdQuarterToWaningCrescentAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 8 and 32, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(2)); + EXPECT_EQ(afterState.mPhase, static_cast(3)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaningCrescentToNewAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 11 and 35, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(3)); + EXPECT_EQ(afterState.mPhase, static_cast(4)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); + } + + TEST(MWWorldWeatherTest, masserPhasesNewToWaxingCrescentAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 14 and 38, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(4)); + EXPECT_EQ(afterState.mPhase, static_cast(5)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 17 and 41, 2:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 17 + 2.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 17 + 2.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 41 + 2.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 41 + 2.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(5)); + EXPECT_EQ(afterState.mPhase, static_cast(6)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); + } + + TEST(MWWorldWeatherTest, masserPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 20 and 44, 5:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 20 + 5.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 20 + 5.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 44 + 5.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 44 + 5.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(6)); + EXPECT_EQ(afterState.mPhase, static_cast(7)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); + } + + TEST(MWWorldWeatherTest, masserPhasesWaxingGibbousToFullAtCorrectTimes) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 35.0f; + + // Days 23 and 47, 8:57 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 23 + 8.0f + 56.0f / 60.0f); + timeStampAfter += (24.0f * 23 + 8.0f + 58.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 47 + 8.0f + 56.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 47 + 8.0f + 58.0f / 60.0f); + + MWWorld::MoonModel moon + = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, + speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(7)); + EXPECT_EQ(afterState.mPhase, static_cast(0)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); + } + } + + // SECUNDA PHASES + + TEST(MWWorldWeatherTest, secundaPhasesFullToWaningGibbousAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 2 and 26, 14:19 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 2 + 14.0f + 18.0f / 60.0f); + timeStampAfter += (24.0f * 2 + 14.0f + 20.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 26 + 14.0f + 18.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 26 + 14.0f + 20.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(0)); + EXPECT_EQ(afterState.mPhase, static_cast(1)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningGibbousToThirdQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 5 and 29, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(1)); + EXPECT_EQ(afterState.mPhase, static_cast(2)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); + } + + TEST(MWWorldWeatherTest, secundaPhasesThirdQuarterToWaningCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(2)); + EXPECT_EQ(afterState.mPhase, static_cast(3)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningCrescentToNewAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 11 and 35, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(3)); + EXPECT_EQ(afterState.mPhase, static_cast(4)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); + } + + TEST(MWWorldWeatherTest, secundaPhasesNewToWaxingCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 14 and 38, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(4)); + EXPECT_EQ(afterState.mPhase, static_cast(5)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 17 and 41, 3:31 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 17 + 3.0f + 30.0f / 60.0f); + timeStampAfter += (24.0f * 17 + 3.0f + 32.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 41 + 3.0f + 30.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 41 + 3.0f + 32.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(5)); + EXPECT_EQ(afterState.mPhase, static_cast(6)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); + } + + TEST(MWWorldWeatherTest, secundaPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 20 and 44, 7:07 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 20 + 7.0f + 6.0f / 60.0f); + timeStampAfter += (24.0f * 20 + 7.0f + 8.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 44 + 7.0f + 6.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 44 + 7.0f + 8.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(6)); + EXPECT_EQ(afterState.mPhase, static_cast(7)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingGibbousToFullAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 23 and 47, 10:43 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 23 + 10.0f + 42.0f / 60.0f); + timeStampAfter += (24.0f * 23 + 10.0f + 44.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 47 + 10.0f + 42.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 47 + 10.0f + 44.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(7)); + EXPECT_EQ(afterState.mPhase, static_cast(0)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); + } + + // OFFSETS + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterFirstLoop) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 3:16 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 8 + 3.0f + 15.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 3.0f + 17.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 32 + 3.0f + 15.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 3.0f + 17.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithLowIncrementShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 0.9f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 7 and 31, 1:44 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 1.0f + 43.0f / 60.0f); + timeStampAfter += (24.0f * 7 + 1.0f + 45.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 1.0f + 43.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 31 + 1.0f + 45.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, masserShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 4 and 28, 1:02 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 1.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 3.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 1.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 3.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 3 and 27, 2:04 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 3 + 2.0f + 3.0f / 60.0f); + timeStampAfter += (24.0f * 3 + 2.0f + 5.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 27 + 2.0f + 3.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 27 + 2.0f + 5.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithIncreasedSpeedShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 1.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 4 and 28, 1:13 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 12.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 14.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 12.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 14.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } +} From 328e98229b6b6faa7178319466bf036bdc633235 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Apr 2025 19:17:19 -0600 Subject: [PATCH 03/15] Fix locked phase typo --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c51ec4b574..dcc60618e4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -525,7 +525,7 @@ namespace MWWorld else { // The moon is locked to Full when it never goes invisible. - return static_cast(1); + return static_cast(0); } } From 303804438a0a43183e08da4a33ef64a476dd5d17 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Thu, 3 Apr 2025 19:46:56 -0600 Subject: [PATCH 04/15] ClangFormat fixes --- apps/openmw/mwworld/weather.cpp | 9 +- apps/openmw/mwworld/weather.hpp | 5 +- apps/openmw_tests/mwworld/testweather.cpp | 921 +++++++++++----------- 3 files changed, 463 insertions(+), 472 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index dcc60618e4..0528134e52 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -423,9 +423,9 @@ namespace MWWorld float moonRiseHourYesterday = moonRiseHourToday - mDailyIncrement; if (moonRiseHourYesterday < 24.0f) { - // Morrowind offsets the increment by -1 when the previous day's visible point crosses into the next day. - // The offset lasts from this point until the next 24-day loop starts. - // To find this point we add mDailyIncrement to the previous visible point and check the result. + // Morrowind offsets the increment by -1 when the previous day's visible point crosses into the next + // day. The offset lasts from this point until the next 24-day loop starts. To find this point we add + // mDailyIncrement to the previous visible point and check the result. float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; float timeToVisible = moonShadowEarlyFadeAngle1 / rotation(1.0f); float cycleOffset = (((moonRiseHourToday >= 24.0f) || (moonRiseHourYesterday + timeToVisible > 24.0f)) @@ -491,8 +491,7 @@ namespace MWWorld // Note that we don't modulo after adding the latest daily increment because other calculations need to // know if doing so would cause the moon rise to be postponed until the next day (which happens when // the moon rise hour is >= 24 in Morrowind). - return mDailyIncrement - + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); + return mDailyIncrement + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); } else { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index fe47722f85..3666496916 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -251,9 +251,8 @@ namespace MWWorld { public: MoonModel(const std::string& name); - MoonModel(const std::string& name, float fadeInStart, - float fadeInFinish, float fadeOutStart, float fadeOutFinish, - float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, + MoonModel(const std::string& name, float fadeInStart, float fadeInFinish, float fadeOutStart, + float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, float moonShadowEarlyFadeAngle); MWRender::MoonState calculateState(const TimeStamp& gameTime) const; diff --git a/apps/openmw_tests/mwworld/testweather.cpp b/apps/openmw_tests/mwworld/testweather.cpp index 2f51ad48e1..5d055d21e5 100644 --- a/apps/openmw_tests/mwworld/testweather.cpp +++ b/apps/openmw_tests/mwworld/testweather.cpp @@ -65,9 +65,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -100,9 +99,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -135,9 +133,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -170,9 +167,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -205,9 +201,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 41 + 2.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 41 + 2.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -240,9 +235,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 44 + 5.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 44 + 5.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -275,9 +269,8 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 47 + 8.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 47 + 8.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon - = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, - speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); MWRender::MoonState afterState = moon.calculateState(timeStampAfter); @@ -289,451 +282,451 @@ namespace MWWorld EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); } - } - // SECUNDA PHASES + // SECUNDA PHASES TEST(MWWorldWeatherTest, secundaPhasesFullToWaningGibbousAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 2 and 26, 14:19 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 2 + 14.0f + 18.0f / 60.0f); - timeStampAfter += (24.0f * 2 + 14.0f + 20.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 26 + 14.0f + 18.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 26 + 14.0f + 20.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(0)); - EXPECT_EQ(afterState.mPhase, static_cast(1)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); - } - - TEST(MWWorldWeatherTest, secundaPhasesWaningGibbousToThirdQuarterAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 5 and 29, 0:00 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); - timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(1)); - EXPECT_EQ(afterState.mPhase, static_cast(2)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); - } - - TEST(MWWorldWeatherTest, secundaPhasesThirdQuarterToWaningCrescentAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 8 and 32, 0:00 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); - timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(2)); - EXPECT_EQ(afterState.mPhase, static_cast(3)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); - } - - TEST(MWWorldWeatherTest, secundaPhasesWaningCrescentToNewAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 11 and 35, 0:00 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); - timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(3)); - EXPECT_EQ(afterState.mPhase, static_cast(4)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); - } - - TEST(MWWorldWeatherTest, secundaPhasesNewToWaxingCrescentAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 14 and 38, 0:00 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); - timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(4)); - EXPECT_EQ(afterState.mPhase, static_cast(5)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); - } - - TEST(MWWorldWeatherTest, secundaPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 17 and 41, 3:31 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 17 + 3.0f + 30.0f / 60.0f); - timeStampAfter += (24.0f * 17 + 3.0f + 32.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 41 + 3.0f + 30.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 41 + 3.0f + 32.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(5)); - EXPECT_EQ(afterState.mPhase, static_cast(6)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); - } - - TEST(MWWorldWeatherTest, secundaPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 20 and 44, 7:07 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 20 + 7.0f + 6.0f / 60.0f); - timeStampAfter += (24.0f * 20 + 7.0f + 8.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 44 + 7.0f + 6.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 44 + 7.0f + 8.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(6)); - EXPECT_EQ(afterState.mPhase, static_cast(7)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); - } - - TEST(MWWorldWeatherTest, secundaPhasesWaxingGibbousToFullAtCorrectTimes) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 23 and 47, 10:43 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 23 + 10.0f + 42.0f / 60.0f); - timeStampAfter += (24.0f * 23 + 10.0f + 44.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 47 + 10.0f + 42.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 47 + 10.0f + 44.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_EQ(beforeState.mPhase, static_cast(7)); - EXPECT_EQ(afterState.mPhase, static_cast(0)); - EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); - EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); - } - - // OFFSETS - - TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterFirstLoop) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 14.0f; - float fadeInFinish = 15.0f; - float fadeOutStart = 7.0f; - float fadeOutFinish = 10.0f; - float axisOffset = 50.0f; - - // Days 8 and 32, 3:16 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 8 + 3.0f + 15.0f / 60.0f); - timeStampAfter += (24.0f * 8 + 3.0f + 17.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 32 + 3.0f + 15.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 32 + 3.0f + 17.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_LE(beforeState.mMoonAlpha, 0.0f); - EXPECT_GT(afterState.mMoonAlpha, 0.0f); - EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); - EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); - } - - TEST(MWWorldWeatherTest, moonWithLowIncrementShouldApplyIncrementOffsetAfterCycle) - { - float dailyIncrement = 0.9f; - float speed = 0.5f; - float fadeEndAngle = 40.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 0.0f; - float fadeInFinish = 0.0f; - float fadeOutStart = 0.0f; - float fadeOutFinish = 0.0f; - float axisOffset = 35.0f; - - // Days 7 and 31, 1:44 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 7 + 1.0f + 43.0f / 60.0f); - timeStampAfter += (24.0f * 7 + 1.0f + 45.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 31 + 1.0f + 43.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 31 + 1.0f + 45.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_LE(beforeState.mMoonAlpha, 0.0f); - EXPECT_GT(afterState.mMoonAlpha, 0.0f); - EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); - EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); - } - - TEST(MWWorldWeatherTest, masserShouldApplyIncrementOffsetAfterCycle) - { - float dailyIncrement = 1.0f; - float speed = 0.5f; - float fadeEndAngle = 40.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 0.0f; - float fadeInFinish = 0.0f; - float fadeOutStart = 0.0f; - float fadeOutFinish = 0.0f; - float axisOffset = 35.0f; - - // Days 4 and 28, 1:02 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 4 + 1.0f + 1.0f / 60.0f); - timeStampAfter += (24.0f * 4 + 1.0f + 3.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 1.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 3.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_LE(beforeState.mMoonAlpha, 0.0f); - EXPECT_GT(afterState.mMoonAlpha, 0.0f); - EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); - EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); - } - - TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterCycle) - { - float dailyIncrement = 1.2f; - float speed = 0.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 0.0f; - float fadeInFinish = 0.0f; - float fadeOutStart = 0.0f; - float fadeOutFinish = 0.0f; - float axisOffset = 50.0f; - - // Days 3 and 27, 2:04 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 3 + 2.0f + 3.0f / 60.0f); - timeStampAfter += (24.0f * 3 + 2.0f + 5.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 27 + 2.0f + 3.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 27 + 2.0f + 5.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_LE(beforeState.mMoonAlpha, 0.0f); - EXPECT_GT(afterState.mMoonAlpha, 0.0f); - EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); - EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); - } - - TEST(MWWorldWeatherTest, moonWithIncreasedSpeedShouldApplyIncrementOffsetAfterCycle) - { - float dailyIncrement = 1.2f; - float speed = 1.6f; - float fadeEndAngle = 30.0f; - float fadeStartAngle = 50.0f; - float moonShadowEarlyFadeAngle = 0.5f; - float fadeInStart = 0.0f; - float fadeInFinish = 0.0f; - float fadeOutStart = 0.0f; - float fadeOutFinish = 0.0f; - float axisOffset = 50.0f; - - // Days 4 and 28, 1:13 - TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; - timeStampBefore += (24.0f * 4 + 1.0f + 12.0f / 60.0f); - timeStampAfter += (24.0f * 4 + 1.0f + 14.0f / 60.0f); - timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 12.0f / 60.0f); - timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 14.0f / 60.0f); - - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, - axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); - - MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); - MWRender::MoonState afterState = moon.calculateState(timeStampAfter); - MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); - MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); - - EXPECT_LE(beforeState.mMoonAlpha, 0.0f); - EXPECT_GT(afterState.mMoonAlpha, 0.0f); - EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); - EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 2 and 26, 14:19 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 2 + 14.0f + 18.0f / 60.0f); + timeStampAfter += (24.0f * 2 + 14.0f + 20.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 26 + 14.0f + 18.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 26 + 14.0f + 20.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(0)); + EXPECT_EQ(afterState.mPhase, static_cast(1)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(0)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(1)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningGibbousToThirdQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 5 and 29, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 5 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(1)); + EXPECT_EQ(afterState.mPhase, static_cast(2)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(1)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(2)); + } + + TEST(MWWorldWeatherTest, secundaPhasesThirdQuarterToWaningCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(2)); + EXPECT_EQ(afterState.mPhase, static_cast(3)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(2)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(3)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaningCrescentToNewAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 11 and 35, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 10 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 11 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(3)); + EXPECT_EQ(afterState.mPhase, static_cast(4)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(3)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(4)); + } + + TEST(MWWorldWeatherTest, secundaPhasesNewToWaxingCrescentAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 14 and 38, 0:00 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 13 + 23.0f + 59.0f / 60.0f); + timeStampAfter += (24.0f * 14 + 0.0f + 1.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(4)); + EXPECT_EQ(afterState.mPhase, static_cast(5)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(4)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(5)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingCrescentToFirstQuarterAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 17 and 41, 3:31 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 17 + 3.0f + 30.0f / 60.0f); + timeStampAfter += (24.0f * 17 + 3.0f + 32.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 41 + 3.0f + 30.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 41 + 3.0f + 32.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(5)); + EXPECT_EQ(afterState.mPhase, static_cast(6)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(5)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(6)); + } + + TEST(MWWorldWeatherTest, secundaPhasesFirstQuarterToWaxingGibbousAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 20 and 44, 7:07 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 20 + 7.0f + 6.0f / 60.0f); + timeStampAfter += (24.0f * 20 + 7.0f + 8.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 44 + 7.0f + 6.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 44 + 7.0f + 8.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(6)); + EXPECT_EQ(afterState.mPhase, static_cast(7)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(6)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(7)); + } + + TEST(MWWorldWeatherTest, secundaPhasesWaxingGibbousToFullAtCorrectTimes) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 23 and 47, 10:43 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 23 + 10.0f + 42.0f / 60.0f); + timeStampAfter += (24.0f * 23 + 10.0f + 44.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 47 + 10.0f + 42.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 47 + 10.0f + 44.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_EQ(beforeState.mPhase, static_cast(7)); + EXPECT_EQ(afterState.mPhase, static_cast(0)); + EXPECT_EQ(beforeStatePostLoop.mPhase, static_cast(7)); + EXPECT_EQ(afterStatePostLoop.mPhase, static_cast(0)); + } + + // OFFSETS + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterFirstLoop) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 14.0f; + float fadeInFinish = 15.0f; + float fadeOutStart = 7.0f; + float fadeOutFinish = 10.0f; + float axisOffset = 50.0f; + + // Days 8 and 32, 3:16 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 8 + 3.0f + 15.0f / 60.0f); + timeStampAfter += (24.0f * 8 + 3.0f + 17.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 32 + 3.0f + 15.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 32 + 3.0f + 17.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithLowIncrementShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 0.9f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 7 and 31, 1:44 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 7 + 1.0f + 43.0f / 60.0f); + timeStampAfter += (24.0f * 7 + 1.0f + 45.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 31 + 1.0f + 43.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 31 + 1.0f + 45.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, masserShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.0f; + float speed = 0.5f; + float fadeEndAngle = 40.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 35.0f; + + // Days 4 and 28, 1:02 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 1.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 3.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 1.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 3.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, secundaShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 0.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 3 and 27, 2:04 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 3 + 2.0f + 3.0f / 60.0f); + timeStampAfter += (24.0f * 3 + 2.0f + 5.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 27 + 2.0f + 3.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 27 + 2.0f + 5.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } + + TEST(MWWorldWeatherTest, moonWithIncreasedSpeedShouldApplyIncrementOffsetAfterCycle) + { + float dailyIncrement = 1.2f; + float speed = 1.6f; + float fadeEndAngle = 30.0f; + float fadeStartAngle = 50.0f; + float moonShadowEarlyFadeAngle = 0.5f; + float fadeInStart = 0.0f; + float fadeInFinish = 0.0f; + float fadeOutStart = 0.0f; + float fadeOutFinish = 0.0f; + float axisOffset = 50.0f; + + // Days 4 and 28, 1:13 + TimeStamp timeStampBefore, timeStampAfter, timeStampBeforePostLoop, timeStampAfterPostLoop; + timeStampBefore += (24.0f * 4 + 1.0f + 12.0f / 60.0f); + timeStampAfter += (24.0f * 4 + 1.0f + 14.0f / 60.0f); + timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 12.0f / 60.0f); + timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 14.0f / 60.0f); + + MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); + + MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); + MWRender::MoonState afterState = moon.calculateState(timeStampAfter); + MWRender::MoonState beforeStatePostLoop = moon.calculateState(timeStampBeforePostLoop); + MWRender::MoonState afterStatePostLoop = moon.calculateState(timeStampAfterPostLoop); + + EXPECT_LE(beforeState.mMoonAlpha, 0.0f); + EXPECT_GT(afterState.mMoonAlpha, 0.0f); + EXPECT_LE(beforeStatePostLoop.mMoonAlpha, 0.0f); + EXPECT_GT(afterStatePostLoop.mMoonAlpha, 0.0f); + } } } From 81cffb461bf7d1f982e879e6d204f6ec9877019e Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 01:12:34 -0600 Subject: [PATCH 05/15] Don't lock the rise or phase hours when always visible --- apps/openmw/mwworld/weather.cpp | 50 +++++++++++---------------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 0528134e52..aad749a84c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -476,29 +476,20 @@ namespace MWWorld inline float MoonModel::moonRiseHour(int gameDay) const { - if (mFadeEndAngle > 0.0f && mFadeEndAngle < 180.0f) - { - // This arises from the start date of 16 Last Seed, 427 - // TODO: Find an alternate formula that doesn't rely on this day being fixed. - static const int startDay = 16; + // This arises from the start date of 16 Last Seed, 427 + // TODO: Find an alternate formula that doesn't rely on this day being fixed. + static const int startDay = 16; - // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. - // The offset increases on the first day of the loop and is multiplied by the number of completed loops. - float incrementOffset = (24.0f - (24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); + // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. + // The offset increases on the first day of the loop and is multiplied by the number of completed loops. + float incrementOffset = (24.0f - (24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); - // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning - // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. - // Note that we don't modulo after adding the latest daily increment because other calculations need to - // know if doing so would cause the moon rise to be postponed until the next day (which happens when - // the moon rise hour is >= 24 in Morrowind). - return mDailyIncrement + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); - } - else - { - // Morrowind uses a fixed rise hour multiplied by daily increment when - // the moon is always visible. - return std::fmod(17.0f * mDailyIncrement, 24.0f); - } + // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning + // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. + // Note that we don't modulo after adding the latest daily increment because other calculations need to + // know if doing so would cause the moon rise to be postponed until the next day (which happens when + // the moon rise hour is >= 24 in Morrowind). + return mDailyIncrement + std::fmod((gameDay - 1 + startDay - incrementOffset) * mDailyIncrement, 24.0f); } inline float MoonModel::rotation(float hours) const @@ -513,19 +504,12 @@ namespace MWWorld { // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day // phase cycle. - if (mFadeEndAngle > 0.0f && mFadeEndAngle < 180.0f) - { - // If the moon didn't rise yet today, use yesterday's moon phase. - if (gameTime.getHour() < moonPhaseHour(gameTime.getDay())) - return static_cast((gameTime.getDay() / 3) % 8); - else - return static_cast(((gameTime.getDay() + 1) / 3) % 8); - } + + // If the moon didn't rise yet today, use yesterday's moon phase. + if (gameTime.getHour() < moonPhaseHour(gameTime.getDay())) + return static_cast((gameTime.getDay() / 3) % 8); else - { - // The moon is locked to Full when it never goes invisible. - return static_cast(0); - } + return static_cast(((gameTime.getDay() + 1) / 3) % 8); } inline bool MoonModel::isVisible(int gameDay, float gameHour) const From 9dcb82108ea7a1fab2f72358ef9f7d4683cd114d Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 16:52:25 -0600 Subject: [PATCH 06/15] Remove mName --- apps/openmw/mwworld/weather.cpp | 5 +-- apps/openmw/mwworld/weather.hpp | 3 +- apps/openmw_tests/mwworld/testweather.cpp | 42 +++++++++++------------ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index aad749a84c..5e3cc2b3d8 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -352,11 +352,10 @@ namespace MWWorld mWeather = 0; } - MoonModel::MoonModel(const std::string& name, float fadeInStart, float fadeInFinish, float fadeOutStart, + MoonModel::MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, float moonShadowEarlyFadeAngle) { - mName = name; mFadeInStart = fadeInStart; mFadeInFinish = fadeInFinish; mFadeOutStart = fadeOutStart; @@ -385,8 +384,6 @@ namespace MWWorld , mFadeEndAngle(Fallback::Map::getFloat("Moons_" + name + "_Fade_End_Angle")) , mMoonShadowEarlyFadeAngle(Fallback::Map::getFloat("Moons_" + name + "_Moon_Shadow_Early_Fade_Angle")) { - mName = name; - // Morrowind appears to have a minimum speed to avoid situations where the moon can't // complete a full rotation in a single 24-hour period. The reverse-engineered formula is // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 3666496916..f8fbab9284 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -251,7 +251,7 @@ namespace MWWorld { public: MoonModel(const std::string& name); - MoonModel(const std::string& name, float fadeInStart, float fadeInFinish, float fadeOutStart, + MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, float moonShadowEarlyFadeAngle); @@ -268,7 +268,6 @@ namespace MWWorld float mFadeStartAngle; float mFadeEndAngle; float mMoonShadowEarlyFadeAngle; - std::string mName; float angle(int gameDay, float gameHour) const; float moonPhaseHour(int gameDay) const; diff --git a/apps/openmw_tests/mwworld/testweather.cpp b/apps/openmw_tests/mwworld/testweather.cpp index 5d055d21e5..4b7fd8f9e2 100644 --- a/apps/openmw_tests/mwworld/testweather.cpp +++ b/apps/openmw_tests/mwworld/testweather.cpp @@ -31,7 +31,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 26 + 11.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 26 + 11.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -65,7 +65,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -99,7 +99,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -133,7 +133,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -167,7 +167,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -201,7 +201,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 41 + 2.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 41 + 2.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -235,7 +235,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 44 + 5.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 44 + 5.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -269,7 +269,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 47 + 8.0f + 56.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 47 + 8.0f + 58.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -305,7 +305,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 26 + 14.0f + 18.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 26 + 14.0f + 20.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -339,7 +339,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 28 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 29 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -373,7 +373,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 31 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 32 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -407,7 +407,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 34 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 35 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -441,7 +441,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 37 + 23.0f + 59.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 38 + 0.0f + 1.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -475,7 +475,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 41 + 3.0f + 30.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 41 + 3.0f + 32.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -509,7 +509,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 44 + 7.0f + 6.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 44 + 7.0f + 8.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -543,7 +543,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 47 + 10.0f + 42.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 47 + 10.0f + 44.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -579,7 +579,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 32 + 3.0f + 15.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 32 + 3.0f + 17.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -613,7 +613,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 31 + 1.0f + 43.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 31 + 1.0f + 45.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -647,7 +647,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 1.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 3.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -681,7 +681,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 27 + 2.0f + 3.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 27 + 2.0f + 5.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); @@ -715,7 +715,7 @@ namespace MWWorld timeStampBeforePostLoop += (24.0f * 28 + 1.0f + 12.0f / 60.0f); timeStampAfterPostLoop += (24.0f * 28 + 1.0f + 14.0f / 60.0f); - MWWorld::MoonModel moon = MWWorld::MoonModel("", fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, + MWWorld::MoonModel moon = MWWorld::MoonModel(fadeInStart, fadeInFinish, fadeOutStart, fadeOutFinish, axisOffset, speed, dailyIncrement, fadeStartAngle, fadeEndAngle, moonShadowEarlyFadeAngle); MWRender::MoonState beforeState = moon.calculateState(timeStampBefore); From 5b5d41f29b5892c26fbf0b54b0bcab10350b291f Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 16:56:31 -0600 Subject: [PATCH 07/15] Change startDay and oneMinute to constexpr --- apps/openmw/mwworld/weather.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5e3cc2b3d8..16bb1f47f2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -475,7 +475,7 @@ namespace MWWorld { // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. - static const int startDay = 16; + constexpr int startDay = 16; // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. // The offset increases on the first day of the loop and is multiplied by the number of completed loops. @@ -512,7 +512,7 @@ namespace MWWorld inline bool MoonModel::isVisible(int gameDay, float gameHour) const { // Morrowind culls the moon one minute before mFadeOutFinish. - static const float oneMinute = 0.0167f; + constexpr float oneMinute = 0.0167f; // The moon isn't visible from mFadeOutFinish to mFadeInStart. if ((gameHour >= (mFadeOutFinish - oneMinute)) && (gameHour < mFadeInStart)) @@ -556,7 +556,7 @@ namespace MWWorld inline float MoonModel::hourlyAlpha(float gameHour) const { // Morrowind culls the moon one minute before mFadeOutFinish - static const float oneMinute = 0.0167f; + constexpr float oneMinute = 0.0167f; float adjustedFadeOutFinish = mFadeOutFinish - oneMinute; // The Fade Out Start / Finish and Fade In Start / Finish describe the hours at which the moon From 7cd243d08a890e241fd0c5c887edc0c3db634dae Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 19:55:17 -0600 Subject: [PATCH 08/15] Clean up visibility conditions --- apps/openmw/mwworld/weather.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 16bb1f47f2..f2df79feac 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -511,23 +511,15 @@ namespace MWWorld inline bool MoonModel::isVisible(int gameDay, float gameHour) const { - // Morrowind culls the moon one minute before mFadeOutFinish. + // The moon is invisible from one minute before mFadeOutFinish to mFadeInStart. constexpr float oneMinute = 0.0167f; - - // The moon isn't visible from mFadeOutFinish to mFadeInStart. - if ((gameHour >= (mFadeOutFinish - oneMinute)) && (gameHour < mFadeInStart)) + if (gameHour >= mFadeOutFinish - oneMinute && gameHour < mFadeInStart) return false; - float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; - float fadeEndAngle2 = 180.0f - mFadeEndAngle; - float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; - - // The moon isn't visible before moonShadowEarlyFadeAngle1 and after moonShadowEarlyFadeAngle2. - float currentAngle = angle(gameDay, gameHour); - if ((currentAngle <= moonShadowEarlyFadeAngle1) || (currentAngle >= moonShadowEarlyFadeAngle2)) - return false; - - return true; + // The moon is visible between moonShadowEarlyFadeAngle1 and the same distance from the end of the sky. + const float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + const float currentAngle = angle(gameDay, gameHour); + return currentAngle > moonShadowEarlyFadeAngle1 && currentAngle < 180.f - moonShadowEarlyFadeAngle1; } inline float MoonModel::shadowBlend(float angle) const From c9685f5bd809ebe9649c121b673facc3ae3282f9 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 20:00:30 -0600 Subject: [PATCH 09/15] Clangformat appeasement --- apps/openmw/mwworld/weather.cpp | 6 +++--- apps/openmw/mwworld/weather.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f2df79feac..96e1c5cf48 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -352,9 +352,9 @@ namespace MWWorld mWeather = 0; } - MoonModel::MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, - float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, - float fadeEndAngle, float moonShadowEarlyFadeAngle) + MoonModel::MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, + float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, + float moonShadowEarlyFadeAngle) { mFadeInStart = fadeInStart; mFadeInFinish = fadeInFinish; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index f8fbab9284..7c27a10316 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -251,9 +251,9 @@ namespace MWWorld { public: MoonModel(const std::string& name); - MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, - float fadeOutFinish, float axisOffset, float speed, float dailyIncrement, float fadeStartAngle, - float fadeEndAngle, float moonShadowEarlyFadeAngle); + MoonModel(float fadeInStart, float fadeInFinish, float fadeOutStart, float fadeOutFinish, float axisOffset, + float speed, float dailyIncrement, float fadeStartAngle, float fadeEndAngle, + float moonShadowEarlyFadeAngle); MWRender::MoonState calculateState(const TimeStamp& gameTime) const; From 647db01978aad1c9c5dfa07273289e949c6b7784 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 4 Apr 2025 23:22:12 -0600 Subject: [PATCH 10/15] Remove phase time delay with negative increment --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 96e1c5cf48..de59f1ef7f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -467,7 +467,7 @@ namespace MWWorld // We can assume that moonShadowEarlyFadeAngle2 > midnightAngle, because the opposite // case would make the moon invisible at midnight, which is checked above. - return ((moonShadowEarlyFadeAngle2 - midnightAngle) / rotation(1.0f)) + mDailyIncrement; + return ((moonShadowEarlyFadeAngle2 - midnightAngle) / rotation(1.0f)) + std::max(mDailyIncrement, 0.0f); } } From 3aab3f5839e742e4b0ebf5cb3e985dd6b35ca1fc Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 5 Apr 2025 00:07:37 -0600 Subject: [PATCH 11/15] Handle zero and negative loop increment offset --- apps/openmw/mwworld/weather.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index de59f1ef7f..2e6da7d03b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -479,7 +479,8 @@ namespace MWWorld // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. // The offset increases on the first day of the loop and is multiplied by the number of completed loops. - float incrementOffset = (24.0f - (24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); + float incrementOffset = (mDailyIncrement == 0.0f) ? + 0.0f : (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. From 45bedc2b10c6fd53d7b057339122801faf73cbd5 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 5 Apr 2025 00:57:58 -0600 Subject: [PATCH 12/15] Clang --- apps/openmw/mwworld/weather.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2e6da7d03b..1b6ff17809 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -479,8 +479,9 @@ namespace MWWorld // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. // The offset increases on the first day of the loop and is multiplied by the number of completed loops. - float incrementOffset = (mDailyIncrement == 0.0f) ? - 0.0f : (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); + float incrementOffset = (mDailyIncrement == 0.0f) + ? 0.0f + : (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. From aaa5431458dae6b29c4c7fa17251b0c24fed5edd Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 5 Apr 2025 23:05:44 -0600 Subject: [PATCH 13/15] Better rise hour edge case handling --- apps/openmw/mwworld/weather.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 1b6ff17809..9f365b5a31 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -473,15 +473,16 @@ namespace MWWorld inline float MoonModel::moonRiseHour(int gameDay) const { + if (mDailyIncrement == 0.0f) + return 0.0f; + // This arises from the start date of 16 Last Seed, 427 // TODO: Find an alternate formula that doesn't rely on this day being fixed. constexpr int startDay = 16; // This formula finds the number of missed increments necessary to make the rise hour a 24-day loop. // The offset increases on the first day of the loop and is multiplied by the number of completed loops. - float incrementOffset = (mDailyIncrement == 0.0f) - ? 0.0f - : (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); + float incrementOffset = (24.0f - std::abs(24.0f / mDailyIncrement)) * std::floor((gameDay + startDay) / 24.0f); // This odd formula arises from the fact that on 16 Last Seed, 17 increments have occurred, meaning // that upon starting a new game, it must only calculate the moon phase as far back as 1 Last Seed. From e546134bfdba60675a2aba76c129e91a5e4f000d Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Sat, 5 Apr 2025 23:25:31 -0600 Subject: [PATCH 14/15] Simplify IsVisible calculation --- apps/openmw/mwworld/weather.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 9f365b5a31..373e87cc79 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -514,15 +514,8 @@ namespace MWWorld inline bool MoonModel::isVisible(int gameDay, float gameHour) const { - // The moon is invisible from one minute before mFadeOutFinish to mFadeInStart. - constexpr float oneMinute = 0.0167f; - if (gameHour >= mFadeOutFinish - oneMinute && gameHour < mFadeInStart) - return false; - - // The moon is visible between moonShadowEarlyFadeAngle1 and the same distance from the end of the sky. - const float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; - const float currentAngle = angle(gameDay, gameHour); - return currentAngle > moonShadowEarlyFadeAngle1 && currentAngle < 180.f - moonShadowEarlyFadeAngle1; + // Moons are "visible" when their alpha value is non-zero. + return hourlyAlpha(gameHour) > 0.f && earlyMoonShadowAlpha(angle(gameDay, gameHour)) > 0.f; } inline float MoonModel::shadowBlend(float angle) const From eb22496e86f8c5253296abddd51b429b4cf3e7b3 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Mon, 7 Apr 2025 00:52:56 -0600 Subject: [PATCH 15/15] Add daily increment modulo and change cycle offset condition --- apps/openmw/mwworld/weather.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 373e87cc79..2ee77458d4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -370,6 +370,10 @@ namespace MWWorld // complete a full rotation in a single 24-hour period. The reverse-engineered formula is // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). mSpeed = std::max(speed, (180.0f / 23.0f / 15.0f)); + + // Morrowind appears to reduce mDailyIncrement with modulo 24.0f to avoid situations where + // the moon would increment more than an entire rotation in a single day. + mDailyIncrement = std::fmod(mDailyIncrement, 24.0f); } MoonModel::MoonModel(const std::string& name) @@ -388,6 +392,10 @@ namespace MWWorld // complete a full rotation in a single 24-hour period. The reverse-engineered formula is // 180 degrees (full hemisphere) / 23 hours / 15 degrees (1 hour travel at speed 1.0). mSpeed = std::max(mSpeed, (180.0f / 23.0f / 15.0f)); + + // Morrowind appears to reduce mDailyIncrement with modulo 24.0f to avoid situations where + // the moon would increment more than an entire rotation in a single day. + mDailyIncrement = std::fmod(mDailyIncrement, 24.0f); } MWRender::MoonState MoonModel::calculateState(const TimeStamp& gameTime) const @@ -425,9 +433,7 @@ namespace MWWorld // mDailyIncrement to the previous visible point and check the result. float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; float timeToVisible = moonShadowEarlyFadeAngle1 / rotation(1.0f); - float cycleOffset = (((moonRiseHourToday >= 24.0f) || (moonRiseHourYesterday + timeToVisible > 24.0f)) - ? mDailyIncrement - : 0.0f); + float cycleOffset = moonRiseHourYesterday + timeToVisible > 24.0f ? mDailyIncrement : 0.0f; float moonRiseAngleYesterday = rotation(24.0f - (moonRiseHourYesterday + cycleOffset)); if (moonRiseAngleYesterday < 180.0f)