From 3235cecddfe11a1bbe70b231b7e1fa8fb716b1db Mon Sep 17 00:00:00 2001
From: slothlife <slothlife@users.noreply.github.com>
Date: Fri, 7 Aug 2015 00:08:18 -0500
Subject: [PATCH] Use Glare View for visibility of celestial bodies

Fixed memory leak from Sun and Moon objects by pulling Updaters back out
into separate objects. Removed code related to
mCelestialBodyTransparency.
---
 apps/openmw/mwrender/sky.cpp    | 235 ++++++++++++++++++--------------
 apps/openmw/mwrender/sky.hpp    |   9 +-
 apps/openmw/mwworld/weather.cpp |  22 ---
 apps/openmw/mwworld/weather.hpp |   6 +-
 4 files changed, 140 insertions(+), 132 deletions(-)

diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp
index f16f97bc2..788848cc4 100644
--- a/apps/openmw/mwrender/sky.cpp
+++ b/apps/openmw/mwrender/sky.cpp
@@ -322,8 +322,7 @@ private:
 };
 
 /// A base class for the sun and moons.
-/// \note Must be stored in an osg::ref_ptr due to being derived from osg::Referenced.
-class CelestialBody : public SceneUtil::StateSetUpdater
+class CelestialBody
 {
 public:
     CelestialBody(osg::Group* parentNode, float scaleFactor, int numUvSets)
@@ -336,14 +335,9 @@ public:
         mTransform->addChild(mGeode);
 
         parentNode->addChild(mTransform);
-
-        mGeode->addUpdateCallback(this);
     }
 
-    virtual ~CelestialBody()
-    {
-        mGeode->removeUpdateCallback(this);
-    }
+    virtual ~CelestialBody() {}
 
     virtual void adjustTransparency(const float ratio) = 0;
 
@@ -365,31 +359,19 @@ class Sun : public CelestialBody
 public:
     Sun(osg::Group* parentNode, Resource::TextureManager& textureManager)
         : CelestialBody(parentNode, 1.0f, 1)
-        , mTextureManager(textureManager)
-        , mColor(0.0f, 0.0f, 0.0f, 1.0f)
+        , mUpdater(new Updater(textureManager))
     {
+        mGeode->addUpdateCallback(mUpdater);
     }
 
-    virtual void setDefaults(osg::StateSet* stateset)
+    ~Sun()
     {
-        osg::ref_ptr<osg::Texture2D> tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds",
-                                                                        osg::Texture::CLAMP,
-                                                                        osg::Texture::CLAMP);
-
-        stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON);
-        stateset->setAttributeAndModes(createUnlitMaterial(),
-                                       osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
-    }
-
-    virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*)
-    {
-        osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
-        mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor);
+        mGeode->removeUpdateCallback(mUpdater);
     }
 
     virtual void adjustTransparency(const float ratio)
     {
-        mColor.a() = ratio;
+        mUpdater->mColor.a() = ratio;
     }
 
     void setDirection(const osg::Vec3f& direction)
@@ -403,8 +385,36 @@ public:
     }
 
 private:
-    Resource::TextureManager& mTextureManager;
-    osg::Vec4f mColor;
+    struct Updater : public SceneUtil::StateSetUpdater
+    {
+        Resource::TextureManager& mTextureManager;
+        osg::Vec4f mColor;
+
+        Updater(Resource::TextureManager& textureManager)
+            : mTextureManager(textureManager)
+            , mColor(0.0f, 0.0f, 0.0f, 1.0f)
+        {
+        }
+
+        virtual void setDefaults(osg::StateSet* stateset)
+        {
+            osg::ref_ptr<osg::Texture2D> tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds",
+                                                                            osg::Texture::CLAMP,
+                                                                            osg::Texture::CLAMP);
+
+            stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON);
+            stateset->setAttributeAndModes(createUnlitMaterial(),
+                                           osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
+        }
+
+        virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*)
+        {
+            osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
+            mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor);
+        }
+    };
+
+    osg::ref_ptr<Updater> mUpdater;
 };
 
 class Moon : public CelestialBody
@@ -418,53 +428,24 @@ public:
 
     Moon(osg::Group* parentNode, Resource::TextureManager& textureManager, float scaleFactor, Type type)
         : CelestialBody(parentNode, scaleFactor, 2)
-        , mTextureManager(textureManager)
         , mType(type)
         , mPhase(MoonState::Phase_Unspecified)
-        , mTransparency(1.0f)
-        , mShadowBlend(1.0f)
-        , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f)
+        , mUpdater(new Updater(textureManager))
     {
         setPhase(MoonState::Phase_Full);
         setVisible(true);
+
+        mGeode->addUpdateCallback(mUpdater);
     }
 
-    virtual void setDefaults(osg::StateSet *stateset)
+    ~Moon()
     {
-        stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON);
-        osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
-        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)); // mShadowBlend * mMoonColor
-        stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON);
-
-        stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON);
-        osg::ref_ptr<osg::TexEnvCombine> texEnv2 = new osg::TexEnvCombine;
-        texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD);
-        texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE);
-        texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE);
-        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)); // mAtmosphereColor.rgb, mTransparency
-        stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON);
-
-        stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
-    }
-
-    virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*)
-    {
-        osg::TexEnvCombine* texEnv = static_cast<osg::TexEnvCombine*>(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV));
-        texEnv->setConstantColor(mMoonColor * mShadowBlend);
-
-        osg::TexEnvCombine* texEnv2 = static_cast<osg::TexEnvCombine*>(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV));
-        texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency));
+        mGeode->removeUpdateCallback(mUpdater);
     }
 
     virtual void adjustTransparency(const float ratio)
     {
-        mTransparency *= ratio;
+        mUpdater->mTransparency *= ratio;
     }
 
     void setState(const MoonState& state)
@@ -484,18 +465,18 @@ public:
         mTransform->setAttitude(attX * rotZ);
 
         setPhase(state.mPhase);
-        mTransparency = state.mMoonAlpha;
-        mShadowBlend = state.mShadowBlend;
+        mUpdater->mTransparency = state.mMoonAlpha;
+        mUpdater->mShadowBlend = state.mShadowBlend;
     }
 
     void setAtmosphereColor(const osg::Vec4f& color)
     {
-        mAtmosphereColor = color;
+        mUpdater->mAtmosphereColor = color;
     }
 
     void setColor(const osg::Vec4f& color)
     {
-        mMoonColor = color;
+        mUpdater->mMoonColor = color;
     }
 
     unsigned int getPhaseInt() const
@@ -512,50 +493,102 @@ public:
     }
 
 private:
-    Resource::TextureManager& mTextureManager;
+    struct Updater : public SceneUtil::StateSetUpdater
+    {
+        Resource::TextureManager& mTextureManager;
+        osg::ref_ptr<osg::Texture2D> mPhaseTex;
+        osg::ref_ptr<osg::Texture2D> mCircleTex;
+        float mTransparency;
+        float mShadowBlend;
+        osg::Vec4f mAtmosphereColor;
+        osg::Vec4f mMoonColor;
+
+        Updater(Resource::TextureManager& textureManager)
+            : mTextureManager(textureManager)
+            , mPhaseTex()
+            , mCircleTex()
+            , mTransparency(1.0f)
+            , mShadowBlend(1.0f)
+            , mAtmosphereColor(1.0f, 1.0f, 1.0f, 1.0f)
+            , mMoonColor(1.0f, 1.0f, 1.0f, 1.0f)
+        {
+        }
+
+        virtual void setDefaults(osg::StateSet* stateset)
+        {
+            stateset->setTextureAttributeAndModes(0, mPhaseTex, osg::StateAttribute::ON);
+            osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
+            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)); // mShadowBlend * mMoonColor
+            stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON);
+
+            stateset->setTextureAttributeAndModes(1, mCircleTex, osg::StateAttribute::ON);
+            osg::ref_ptr<osg::TexEnvCombine> texEnv2 = new osg::TexEnvCombine;
+            texEnv2->setCombine_RGB(osg::TexEnvCombine::ADD);
+            texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE);
+            texEnv2->setSource0_Alpha(osg::TexEnvCombine::TEXTURE);
+            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)); // mAtmosphereColor.rgb, mTransparency
+            stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON);
+
+            stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
+        }
+
+        virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*)
+        {
+            osg::TexEnvCombine* texEnv = static_cast<osg::TexEnvCombine*>(stateset->getTextureAttribute(0, osg::StateAttribute::TEXENV));
+            texEnv->setConstantColor(mMoonColor * mShadowBlend);
+
+            osg::TexEnvCombine* texEnv2 = static_cast<osg::TexEnvCombine*>(stateset->getTextureAttribute(1, osg::StateAttribute::TEXENV));
+            texEnv2->setConstantColor(osg::Vec4f(mAtmosphereColor.x(), mAtmosphereColor.y(), mAtmosphereColor.z(), mTransparency));
+        }
+
+        void setTextures(const std::string& phaseTex, const std::string& circleTex)
+        {
+            mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP);
+            mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP);
+
+            reset();
+        }
+    };
+
     Type mType;
     MoonState::Phase mPhase;
-    float mTransparency;
-    float mShadowBlend;
-    osg::Vec4f mAtmosphereColor;
-    osg::Vec4f mMoonColor;
-    osg::ref_ptr<osg::Texture2D> mPhaseTex;
-    osg::ref_ptr<osg::Texture2D> mCircleTex;
-
-    void setTextures(const std::string& phaseTex, const std::string& circleTex)
-    {
-        mPhaseTex = mTextureManager.getTexture2D(phaseTex, osg::Texture::CLAMP, osg::Texture::CLAMP);
-        mCircleTex = mTextureManager.getTexture2D(circleTex, osg::Texture::CLAMP, osg::Texture::CLAMP);
-
-        reset();
-    }
+    osg::ref_ptr<Updater> mUpdater;
 
     void setPhase(const MoonState::Phase& phase)
     {
-        if (mPhase == phase)
+        if(mPhase == phase)
             return;
+
         mPhase = phase;
 
         std::string textureName = "textures/tx_";
 
-        if (mType == Moon::Type_Secunda) textureName += "secunda_";
-        else textureName += "masser_";
+        if (mType == Moon::Type_Secunda)
+            textureName += "secunda_";
+        else
+            textureName += "masser_";
 
-        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";
+        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";
 
         if (mType == Moon::Type_Secunda)
-            setTextures(textureName, "textures/tx_mooncircle_full_s.dds");
+            mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_s.dds");
         else
-            setTextures(textureName, "textures/tx_mooncircle_full_m.dds");
+            mUpdater->setTextures(textureName, "textures/tx_mooncircle_full_m.dds");
     }
 };
 
@@ -621,11 +654,11 @@ void SkyManager::create()
     mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager());
     atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater);
 
-    mSun = new Sun(mRootNode, *mSceneManager->getTextureManager());
+    mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager()));
 
     const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback();
-    mMasser = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser);
-    mSecunda = new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda);
+    mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser));
+    mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda));
 
     mCloudNode = new osg::PositionAttitudeTransform;
     mRootNode->addChild(mCloudNode);
@@ -1067,11 +1100,11 @@ void SkyManager::setWeather(const WeatherResult& weather)
 
     mCloudSpeed = weather.mCloudSpeed;
 
-    mMasser->adjustTransparency(weather.mCelestialBodyTransparency);
-    mSecunda->adjustTransparency(weather.mCelestialBodyTransparency);
-    mSun->adjustTransparency(weather.mCelestialBodyTransparency);
+    mMasser->adjustTransparency(weather.mGlareView);
+    mSecunda->adjustTransparency(weather.mGlareView);
+    mSun->adjustTransparency(weather.mGlareView);
 
-    float nextStarsOpacity = weather.mNightFade * weather.mCelestialBodyTransparency;
+    float nextStarsOpacity = weather.mNightFade * weather.mGlareView;
     if(weather.mNight && mStarsOpacity != nextStarsOpacity)
     {
         mStarsOpacity = nextStarsOpacity;
diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp
index 16509ef32..4b1acadc3 100644
--- a/apps/openmw/mwrender/sky.hpp
+++ b/apps/openmw/mwrender/sky.hpp
@@ -2,6 +2,7 @@
 #define OPENMW_MWRENDER_SKY_H
 
 #include <string>
+#include <memory>
 
 #include <osg/ref_ptr>
 #include <osg/Vec4f>
@@ -75,8 +76,6 @@ namespace MWRender
 
         float mRainSpeed;
         float mRainFrequency;
-
-        float mCelestialBodyTransparency;
     };
 
     struct MoonState
@@ -179,9 +178,9 @@ namespace MWRender
 
         osg::ref_ptr<AtmosphereUpdater> mAtmosphereUpdater;
 
-        osg::ref_ptr<Sun> mSun;
-        osg::ref_ptr<Moon> mMasser;
-        osg::ref_ptr<Moon> mSecunda;
+        std::auto_ptr<Sun> mSun;
+        std::auto_ptr<Moon> mMasser;
+        std::auto_ptr<Moon> mSecunda;
 
         osg::ref_ptr<osg::Group> mRainNode;
         osg::ref_ptr<osgParticle::ParticleSystem> mRainParticleSystem;
diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp
index 679565e45..c571b1d1d 100644
--- a/apps/openmw/mwworld/weather.cpp
+++ b/apps/openmw/mwworld/weather.cpp
@@ -294,54 +294,44 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::F
 
     //Weather
     Weather clear;
-    clear.mObstructsCelestialBodies = false;
     setFallbackWeather(clear,"clear");
 
     Weather cloudy;
-    cloudy.mObstructsCelestialBodies = false;
     setFallbackWeather(cloudy,"cloudy");
 
     Weather foggy;
-    foggy.mObstructsCelestialBodies = false;
     setFallbackWeather(foggy,"foggy");
 
     Weather thunderstorm;
     thunderstorm.mAmbientLoopSoundID = "rain heavy";
     thunderstorm.mRainEffect = "meshes\\raindrop.nif";
-    thunderstorm.mObstructsCelestialBodies = true;
     setFallbackWeather(thunderstorm,"thunderstorm");
 
     Weather rain;
     rain.mAmbientLoopSoundID = "rain";
     rain.mRainEffect = "meshes\\raindrop.nif";
-    rain.mObstructsCelestialBodies = true;
     setFallbackWeather(rain,"rain");
 
     Weather overcast;
-    overcast.mObstructsCelestialBodies = true;
     setFallbackWeather(overcast,"overcast");
 
     Weather ashstorm;
     ashstorm.mAmbientLoopSoundID = "ashstorm";
     ashstorm.mParticleEffect = "meshes\\ashcloud.nif";
-    ashstorm.mObstructsCelestialBodies = true;
     setFallbackWeather(ashstorm,"ashstorm");
 
     Weather blight;
     blight.mAmbientLoopSoundID = "blight";
     blight.mParticleEffect = "meshes\\blightcloud.nif";
-    blight.mObstructsCelestialBodies = true;
     setFallbackWeather(blight,"blight");
 
     Weather snow;
     snow.mParticleEffect = "meshes\\snow.nif";
-    snow.mObstructsCelestialBodies = true;
     setFallbackWeather(snow, "snow");
 
     Weather blizzard;
     blizzard.mAmbientLoopSoundID = "BM Blizzard";
     blizzard.mParticleEffect = "meshes\\blizzard.nif";
-    blizzard.mObstructsCelestialBodies = true;
     setFallbackWeather(blizzard,"blizzard");
 }
 
@@ -475,8 +465,6 @@ void WeatherManager::setResult(const std::string& weatherType)
             mResult.mNightFade = factor;
         }
     }
-
-    mResult.mCelestialBodyTransparency = current.mObstructsCelestialBodies ? 0.0f : 1.0f;
 }
 
 void WeatherManager::transition(float factor)
@@ -530,16 +518,6 @@ void WeatherManager::transition(float factor)
         mResult.mEffectFade = mResult.mAmbientSoundVolume;
         mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID;
     }
-
-    const Weather& currentSettings = mWeatherSettings[mCurrentWeather];
-    const Weather& nextSettings = mWeatherSettings[mNextWeather];
-
-    if(currentSettings.mObstructsCelestialBodies && !nextSettings.mObstructsCelestialBodies)
-        mResult.mCelestialBodyTransparency = factor;
-    else if(!currentSettings.mObstructsCelestialBodies && nextSettings.mObstructsCelestialBodies)
-        mResult.mCelestialBodyTransparency = 1 - factor;
-    else
-        mResult.mCelestialBodyTransparency = current.mCelestialBodyTransparency;
 }
 
 void WeatherManager::update(float duration, bool paused)
diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp
index 1bc3bc357..d5ac6d801 100644
--- a/apps/openmw/mwworld/weather.hpp
+++ b/apps/openmw/mwworld/weather.hpp
@@ -80,7 +80,8 @@ namespace MWWorld
         // Multiplier for clouds transparency
         float mCloudsMaximumPercent;
 
-        // Value between 0 and 1, defines the strength of the sun glare effect
+        // Value between 0 and 1, defines the strength of the sun glare effect.
+        // Also appears to modify how visible the sun, moons, and stars are for various weather effects.
         float mGlareView;
 
         // Sound effect
@@ -106,9 +107,6 @@ namespace MWWorld
 
         // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
         // is broken in the vanilla game and was disabled.
-
-        // Some weather patterns will obstruct the moons, sun, and stars.
-        bool mObstructsCelestialBodies;
     };
 
     class MoonModel