From 24ba54f4feb65161e306cba91b3270aa6efcdbfb Mon Sep 17 00:00:00 2001 From: slothlife Date: Wed, 29 Jul 2015 23:57:45 -0500 Subject: [PATCH] Implement accurate moon settings (fixes #672) --- apps/openmw/mwrender/sky.cpp | 162 ++++++++------------ apps/openmw/mwrender/sky.hpp | 37 +++-- apps/openmw/mwworld/weather.cpp | 264 ++++++++++++++++++++------------ apps/openmw/mwworld/weather.hpp | 35 ++++- 4 files changed, 290 insertions(+), 208 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 49c00c33d7..cf20bc4c6d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,5 +1,8 @@ #include "sky.hpp" +#define _USE_MATH_DEFINES +#include + #include #include #include @@ -383,26 +386,29 @@ public: Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) : CelestialBody(parentNode, sceneManager, scaleFactor, 2) , mType(type) - , mPhase(Phase_Unspecified) + , mPhase(MoonState::Phase_Unspecified) { mUpdater = new MoonUpdater; mGeode->addUpdateCallback(mUpdater); - setPhase(Phase_WaxingCrescent); + setPhase(MoonState::Phase_Full); + setVisible(true); } - enum Phase + void setState(const MoonState& state) { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent, - Phase_Unspecified - }; + float radsX = ((state.mRotationFromHorizon) * M_PI) / 180.0f; + float radsY = 0; + float radsZ = ((state.mRotationFromNorth) * M_PI) / 180.0f; + + osg::Quat rotation(radsX, osg::Vec3f(1.0f, 0.0f, 0.0f), + radsY, osg::Vec3f(0.0f, 1.0f, 0.0f), + radsZ, osg::Vec3f(0.0f, 0.0f, 1.0f)); + setDirection(rotation * osg::Vec3f(0.0f, 1.0f, 0.0f)); + setPhase(state.mPhase); + setTransparency(state.mMoonAlpha); + setShadowBlend(state.mShadowBlend); + } void setTextures(const std::string& phaseTex, const std::string& circleTex) { @@ -415,7 +421,7 @@ public: mUpdater->setTextures(phaseTexPtr, circleTexPtr); } - void setPhase(const Phase& phase) + void setPhase(const MoonState::Phase& phase) { if (mPhase == phase) return; @@ -426,14 +432,14 @@ public: if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; + if (phase == MoonState::Phase_New) textureName += "new"; + else if (phase == MoonState::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == MoonState::Phase_FirstQuarter) textureName += "half_wax"; + else if (phase == MoonState::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == MoonState::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == MoonState::Phase_ThirdQuarter) textureName += "half_wan"; + else if (phase == MoonState::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == MoonState::Phase_Full) textureName += "full"; textureName += ".dds"; @@ -452,7 +458,8 @@ public: { public: MoonUpdater() - : mFade(0.f) + : mTransparency(1.0f) + , mShadowBlend(1.0f) , mMoonColor(1,1,1,1) { } @@ -464,7 +471,7 @@ public: texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); - texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // fade * MoonRedColor + texEnv->setConstantColor(osg::Vec4f(1.f, 0.f, 0.f, 1.f)); // mShadowBlend * mMoonColor stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON); @@ -475,7 +482,7 @@ public: texEnv2->setSource1_Alpha(osg::TexEnvCombine::CONSTANT); texEnv2->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); texEnv2->setSource1_RGB(osg::TexEnvCombine::CONSTANT); - texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + texEnv2->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // mAtmosphereColor.rgb, mTransparency stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); @@ -484,21 +491,20 @@ public: virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) { osg::TexEnvCombine* texEnv = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV)); - texEnv->setConstantColor(mMoonColor * mFade); + texEnv->setConstantColor(mMoonColor * mShadowBlend); osg::TexEnvCombine* texEnv2 = static_cast(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV)); - const float backdropFadeThreshold = 0.03; - if (mFade <= backdropFadeThreshold) - { - texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mFade / backdropFadeThreshold)); - } - else - texEnv2->setConstantColor(mAtmosphereColor); + texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency)); } - void setFade (const float fade) + void setTransparency(const float ratio) { - mFade = fade; + mTransparency = ratio; + } + + void setShadowBlend(const float blendFactor) + { + mShadowBlend = blendFactor; } void setAtmosphereColor(const osg::Vec4f& color) @@ -519,7 +525,8 @@ public: } private: - float mFade; + float mTransparency; + float mShadowBlend; osg::Vec4f mAtmosphereColor; osg::Vec4f mMoonColor; osg::ref_ptr mPhaseTex; @@ -537,27 +544,32 @@ public: mUpdater->setMoonColor(color); } - void setFade(const float fade) + void setTransparency(const float ratio) { - mUpdater->setFade(fade); + mUpdater->setTransparency(ratio); + } + + void setShadowBlend(const float blendFactor) + { + mUpdater->setShadowBlend(blendFactor); } unsigned int getPhaseInt() const { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; + if (mPhase == MoonState::Phase_New) return 0; + else if (mPhase == MoonState::Phase_WaxingCrescent) return 1; + else if (mPhase == MoonState::Phase_WaningCrescent) return 1; + else if (mPhase == MoonState::Phase_FirstQuarter) return 2; + else if (mPhase == MoonState::Phase_ThirdQuarter) return 2; + else if (mPhase == MoonState::Phase_WaxingGibbous) return 3; + else if (mPhase == MoonState::Phase_WaningGibbous) return 3; + else if (mPhase == MoonState::Phase_Full) return 4; return 0; } private: Type mType; - Phase mPhase; + MoonState::Phase mPhase; osg::ref_ptr mUpdater; }; @@ -886,10 +898,6 @@ void SkyManager::update(float duration) mCloudUpdater->setAnimationTimer(mCloudAnimationTimer); mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer); - /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - if (mSunEnabled) { // take 1/10 sec for fading the glare effect from invisible to full @@ -1128,46 +1136,18 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const osg::Vec3f& direction) +void SkyManager::setMasserState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mMasser->setDirection(direction); + mMasser->setState(state); } -void SkyManager::setSecundaDirection(const osg::Vec3f& direction) +void SkyManager::setSecundaState(const MoonState& state) { - if (!mCreated) return; + if(!mCreated) return; - mSecunda->setDirection(direction); -} - -void SkyManager::masserEnable() -{ - if (!mCreated) return; - - mMasser->setVisible(true); -} - -void SkyManager::secundaEnable() -{ - if (!mCreated) return; - - mSecunda->setVisible(true); -} - -void SkyManager::masserDisable() -{ - if (!mCreated) return; - - mMasser->setVisible(false); -} - -void SkyManager::secundaDisable() -{ - if (!mCreated) return; - - mSecunda->setVisible(false); + mSecunda->setState(state); } void SkyManager::setLightningStrength(const float factor) @@ -1184,18 +1164,6 @@ void SkyManager::setLightningStrength(const float factor) */ } -void SkyManager::setMasserFade(const float fade) -{ - if (!mCreated) return; - mMasser->setFade(fade); -} - -void SkyManager::setSecundaFade(const float fade) -{ - if (!mCreated) return; - mSecunda->setFade(fade); -} - void SkyManager::setDate(int day, int month) { mDay = day; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4d1c73e446..eb953d1285 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -33,6 +33,28 @@ namespace MWRender class RainFader; class AlphaFader; + struct MoonState + { + enum Phase + { + Phase_Full = 0, + Phase_WaningGibbous, + Phase_ThirdQuarter, + Phase_WaningCrescent, + Phase_New, + Phase_WaxingCrescent, + Phase_FirstQuarter, + Phase_WaxingGibbous, + Phase_Unspecified + }; + + float mRotationFromHorizon; + float mRotationFromNorth; + Phase mPhase; + float mShadowBlend; + float mMoonAlpha; + }; + class SkyManager { public: @@ -72,19 +94,8 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const osg::Vec3f& direction); - - void setSecundaDirection(const osg::Vec3f& direction); - - void setMasserFade(const float fade); - - void setSecundaFade(const float fade); - - void masserEnable(); - void masserDisable(); - - void secundaEnable(); - void secundaDisable(); + void setMasserState(const MoonState& state); + void setSecundaState(const MoonState& state); void setLightningStrength(const float factor); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 970e8b4553..f98aa24c13 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -37,6 +37,170 @@ namespace } } +MoonModel::MoonModel(const std::string& name, MWWorld::Fallback& fallback) + : mFadeInStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Start")) + , mFadeInFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_In_Finish")) + , mFadeOutStart(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Start")) + , mFadeOutFinish(fallback.getFallbackFloat("Moons_" + name + "_Fade_Out_Finish")) + , mAxisOffset(fallback.getFallbackFloat("Moons_" + name + "_Axis_Offset")) + , mSpeed(fallback.getFallbackFloat("Moons_" + name + "_Speed")) + , mDailyIncrement(fallback.getFallbackFloat("Moons_" + name + "_Daily_Increment")) + , mFadeStartAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_Start_Angle")) + , mFadeEndAngle(fallback.getFallbackFloat("Moons_" + name + "_Fade_End_Angle")) + , mMoonShadowEarlyFadeAngle(fallback.getFallbackFloat("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); +} + +MWRender::MoonState MoonModel::calculateState(unsigned int daysPassed, float gameHour) +{ + float rotationFromHorizon = angle(daysPassed, gameHour); + MWRender::MoonState state = + { + rotationFromHorizon, + mAxisOffset, // Reverse engineered from Morrowind's scene graph rotation matrices. + static_cast(phase(daysPassed)), + shadowBlend(rotationFromHorizon), + earlyMoonShadowAlpha(rotationFromHorizon) * hourlyAlpha(gameHour) + }; + + return state; +} + +inline float MoonModel::angle(unsigned int daysPassed, float gameHour) +{ + // 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 rise. + + // When calculating the angle of the moon, several cases have to be taken into account: + // 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(daysPassed); + float moonRiseAngleToday = 0; + + if(gameHour < moonRiseHourToday) + { + float moonRiseHourYesterday = moonRiseHour(daysPassed - 1); + if(moonRiseHourYesterday < 24) + { + float moonRiseAngleYesterday = rotation(24 - moonRiseHourYesterday); + if(moonRiseAngleYesterday < 180) + { + // The moon rose but did not set yesterday, so accumulate yesterday's angle with how much we've travelled today. + moonRiseAngleToday = rotation(gameHour) + moonRiseAngleYesterday; + } + } + } + else + { + moonRiseAngleToday = rotation(gameHour - moonRiseHourToday); + } + + if(moonRiseAngleToday >= 180) + { + // The moon set today, reset the angle to the horizon. + moonRiseAngleToday = 0; + } + + return moonRiseAngleToday; +} + +inline float MoonModel::moonRiseHour(unsigned int daysPassed) +{ + // 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; + + // 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); +} + +inline float MoonModel::rotation(float hours) +{ + // 15 degrees per hour was reverse engineered from the rotation matrices of the Morrowind scene graph. + // Note that this correlates to 360 / 24, which is a full rotation every 24 hours, so speed is a measure + // of whole rotations that could be completed in a day. + return 15.0f * mSpeed * hours; +} + +inline unsigned int MoonModel::phase(unsigned int daysPassed) +{ + // Morrowind starts with a full moon on 16 Last Seed and then begins to wane 17 Last Seed, working on 3 day phase cycle. + // Note: this is an internal helper, and as such we don't want to return MWRender::MoonState::Phase since we can't + // forward declare it (C++11 strongly typed enums solve this). + return ((daysPassed + 1) / 3) % 8; +} + +inline float MoonModel::shadowBlend(float angle) +{ + // The Fade End Angle and Fade Start Angle describe a region where the moon transitions from a solid disk + // that is roughly the color of the sky, to a textured surface. + // Depending on the current angle, the following values describe the ratio between the textured moon + // and the solid disk: + // 1. From Fade End Angle 1 to Fade Start Angle 1 (during moon rise): 0..1 + // 2. From Fade Start Angle 1 to Fade Start Angle 2 (between moon rise and moon set): 1 (textured) + // 3. From Fade Start Angle 2 to Fade End Angle 2 (during moon set): 1..0 + // 4. From Fade End Angle 2 to Fade End Angle 1 (between moon set and moon rise): 0 (solid disk) + float fadeAngle = mFadeStartAngle - mFadeEndAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float fadeStartAngle2 = 180.0f - mFadeStartAngle; + if((angle >= mFadeEndAngle) && (angle < mFadeStartAngle)) + return (angle - mFadeEndAngle) / fadeAngle; + else if((angle >= mFadeStartAngle) && (angle < fadeStartAngle2)) + return 1.0f; + else if((angle >= fadeStartAngle2) && (angle < fadeEndAngle2)) + return (fadeEndAngle2 - angle) / fadeAngle; + else + return 0.0f; +} + +inline float MoonModel::hourlyAlpha(float gameHour) +{ + // 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. + // 1. From Fade Out Start to Fade Out Finish: 1..0 + // 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)) + return 0.0f; + else if((gameHour >= mFadeInStart) && (gameHour < mFadeInFinish)) + return (gameHour - mFadeInStart) / (mFadeInFinish - mFadeInStart); + else + return 1.0f; +} + +inline float MoonModel::earlyMoonShadowAlpha(float angle) +{ + // The Moon Shadow Early Fade Angle describes an arc relative to Fade End Angle. + // Depending on the current angle, the following values describe how transparent the moon is. + // 1. From Moon Shadow Early Fade Angle 1 to Fade End Angle 1 (during moon rise): 0..1 + // 2. From Fade End Angle 1 to Fade End Angle 2 (between moon rise and moon set): 1 (solid) + // 3. From Fade End Angle 2 to Moon Shadow Early Fade Angle 2 (during moon set): 1..0 + // 4. From Moon Shadow Early Fade Angle 2 to Moon Shadow Early Fade Angle 1: 0 (transparent) + float moonShadowEarlyFadeAngle1 = mFadeEndAngle - mMoonShadowEarlyFadeAngle; + float fadeEndAngle2 = 180.0f - mFadeEndAngle; + float moonShadowEarlyFadeAngle2 = fadeEndAngle2 + mMoonShadowEarlyFadeAngle; + if((angle >= moonShadowEarlyFadeAngle1) && (angle < mFadeEndAngle)) + return (angle - moonShadowEarlyFadeAngle1) / mMoonShadowEarlyFadeAngle; + else if((angle >= mFadeEndAngle) && (angle < fadeEndAngle2)) + return 1.0f; + else if((angle >= fadeEndAngle2) && (angle < moonShadowEarlyFadeAngle2)) + return (moonShadowEarlyFadeAngle2 - angle) / mMoonShadowEarlyFadeAngle; + else + return 0.0f; +} + void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { std::string upper=name; @@ -88,39 +252,12 @@ Max Raindrops=650 ? mWeatherSettings[name] = weather; } - -float WeatherManager::calculateHourFade (const std::string& moonName) const -{ - float fadeOutStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Start"); - float fadeOutFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Start"); - float fadeInFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Finish"); - - if (mHour >= fadeOutStart && mHour <= fadeOutFinish) - return (1 - ((mHour - fadeOutStart) / (fadeOutFinish - fadeOutStart))); - if (mHour >= fadeInStart && mHour <= fadeInFinish) - return (1 - ((mHour - fadeInStart) / (fadeInFinish - fadeInStart))); - else - return 1; -} - -float WeatherManager::calculateAngleFade (const std::string& moonName, float angle) const -{ - float endAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_End_Angle"); - float startAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Start_Angle"); - if (angle <= startAngle && angle >= endAngle) - return (1 - ((angle - endAngle)/(startAngle-endAngle))); - else if (angle > startAngle) - return 0.f; - else - return 1.f; -} - WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) : mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store), mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), - mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0) + mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0), + mMasser("Masser", *fallback), mSecunda("Secunda", *fallback) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -465,72 +602,9 @@ void WeatherManager::update(float duration, bool paused) mRendering->setSunDirection( final * -1 ); } - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - osg::Vec3f masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - osg::Vec3f secunda( - (moonHeight - 1) * facing * 1.25f, - (1 - moonHeight) * facing * 0.8f, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - if (masserAngleFade > 0) - { - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->masserEnable(); - } - else - mRendering->getSkyManager()->masserDisable(); - - if (secundaAngleFade > 0) - { - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - mRendering->getSkyManager()->secundaEnable(); - } - else - mRendering->getSkyManager()->secundaDisable(); - - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } + TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); + mRendering->getSkyManager()->setMasserState(mMasser.calculateState(time.getDay(), time.getHour())); + mRendering->getSkyManager()->setSecundaState(mSecunda.calculateState(time.getDay(), time.getHour())); if (!paused) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index efe69f17cb..93cfed68bf 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -19,6 +19,7 @@ namespace ESM namespace MWRender { class RenderingManager; + class MoonState; } namespace Loading @@ -150,6 +151,35 @@ namespace MWWorld // is broken in the vanilla game and was disabled. }; + class MoonModel + { + public: + MoonModel(const std::string& name, MWWorld::Fallback& fallback); + + MWRender::MoonState calculateState(unsigned int daysPassed, float gameHour); + + private: + float mSize; + float mFadeInStart; + float mFadeInFinish; + float mFadeOutStart; + float mFadeOutFinish; + float mAxisOffset; + float mSpeed; + float mDailyIncrement; + float mFadeStartAngle; + float mFadeEndAngle; + float mMoonShadowEarlyFadeAngle; + + float angle(unsigned int daysPassed, float gameHour); + float moonRiseHour(unsigned int daysPassed); + float rotation(float hours); + unsigned int phase(unsigned int daysPassed); + float shadowBlend(float angle); + float hourlyAlpha(float gameHour); + float earlyMoonShadowAlpha(float angle); + }; + /// /// Interface for weather settings /// @@ -237,9 +267,6 @@ namespace MWWorld void transition(const float factor); void setResult(const std::string& weatherType); - float calculateHourFade (const std::string& moonName) const; - float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const std::string& weatherType, bool instant=false); std::string nextWeather(const ESM::Region* region) const; WeatherResult mResult; @@ -265,6 +292,8 @@ namespace MWWorld std::string mThunderSoundID1; std::string mThunderSoundID2; std::string mThunderSoundID3; + MoonModel mMasser; + MoonModel mSecunda; }; }