From 2161788711f6d89564afc933707b6a0b8c1b0562 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Fri, 20 Oct 2017 16:37:03 -0700
Subject: Day cycles start

---
 indra/newview/llenvironment.cpp      |  38 +++++--
 indra/newview/llenvironment.h        |   5 +
 indra/newview/llsettingsbase.cpp     |  12 ++
 indra/newview/llsettingsbase.h       |   7 +-
 indra/newview/llsettingsdaycycle.cpp | 210 ++++++++++++++++++++++++++++++++++-
 indra/newview/llsettingsdaycycle.h   |  42 +++++--
 indra/newview/llsettingssky.cpp      |  11 ++
 indra/newview/llsettingssky.h        |   2 +
 indra/newview/llsettingswater.cpp    |  11 ++
 indra/newview/llsettingswater.h      |   2 +-
 10 files changed, 318 insertions(+), 22 deletions(-)

diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 921f3ef910..fbb713c6d8 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -293,15 +293,14 @@ void LLEnvironment::clearAllSkys()
 
 void LLEnvironment::selectSky(const std::string &name)
 {
-    NamedSettingMap_t::iterator it = mSkysByName.find(name);
-
-    if (it == mSkysByName.end())
+    LLSettingsSky::ptr_t next_sky = findSkyByName(name);
+    if (!next_sky)
     {
         LL_WARNS("ENVIRONMENT") << "Unable to select sky with unknown name '" << name << "'" << LL_ENDL;
         return;
     }
 
-    mCurrentSky = boost::static_pointer_cast<LLSettingsSky>((*it).second);
+    mCurrentSky = next_sky;
     mCurrentSky->setDirtyFlag(true);
 }
 
@@ -322,15 +321,15 @@ void LLEnvironment::addWater(const LLSettingsWater::ptr_t &water)
 
 void LLEnvironment::selectWater(const std::string &name)
 {
-    NamedSettingMap_t::iterator it = mWaterByName.find(name);
+    LLSettingsWater::ptr_t next_water = findWaterByName(name);
 
-    if (it == mWaterByName.end())
+    if (!next_water)
     {
         LL_WARNS("ENVIRONMENT") << "Unable to select water with unknown name '" << name << "'" << LL_ENDL;
         return;
     }
 
-    mCurrentWater = boost::static_pointer_cast<LLSettingsWater>((*it).second);
+    mCurrentWater = next_water;
     mCurrentWater->setDirtyFlag(true);
 }
 
@@ -348,6 +347,31 @@ void LLEnvironment::clearAllWater()
     mWaterById.clear();
 }
 
+LLSettingsSky::ptr_t LLEnvironment::findSkyByName(std::string name) const
+{
+    NamedSettingMap_t::const_iterator it = mSkysByName.find(name);
+
+    if (it == mSkysByName.end())
+    {
+        LL_WARNS("ENVIRONMENT") << "Unable to find sky with unknown name '" << name << "'" << LL_ENDL;
+        return LLSettingsSky::ptr_t();
+    }
+
+    return boost::static_pointer_cast<LLSettingsSky>((*it).second);
+}
+
+LLSettingsWater::ptr_t LLEnvironment::findWaterByName(std::string name) const
+{
+    NamedSettingMap_t::const_iterator it = mWaterByName.find(name);
+
+    if (it == mWaterByName.end())
+    {
+        LL_WARNS("ENVIRONMENT") << "Unable to find water with unknown name '" << name << "'" << LL_ENDL;
+        return LLSettingsWater::ptr_t();
+    }
+
+    return boost::static_pointer_cast<LLSettingsWater>((*it).second);
+}
 
 //=========================================================================
 LLEnvironment::UserPrefs::UserPrefs():
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index 7506b37e3e..493fff1769 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -85,6 +85,8 @@ public:
     LLSettingsSky::ptr_t    getCurrentSky() const { return mCurrentSky; }
     LLSettingsWater::ptr_t  getCurrentWater() const { return mCurrentWater; }
 
+
+
     void                    update(const LLViewerCamera * cam);
 
     void                    updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting);
@@ -92,6 +94,9 @@ public:
 
     void                    addSky(const LLSettingsSky::ptr_t &sky);
     void                    selectSky(const std::string &name);
+    LLSettingsSky::ptr_t    findSkyByName(std::string name) const;
+    LLSettingsWater::ptr_t  findWaterByName(std::string name) const;
+
     void                    addWater(const LLSettingsWater::ptr_t &sky);
     void                    selectWater(const std::string &name);
 
diff --git a/indra/newview/llsettingsbase.cpp b/indra/newview/llsettingsbase.cpp
index 71ec240214..1f155776bf 100644
--- a/indra/newview/llsettingsbase.cpp
+++ b/indra/newview/llsettingsbase.cpp
@@ -240,6 +240,18 @@ LLSD LLSettingsBase::cloneSettings() const
     return combineSDMaps(mSettings, LLSD());
 }
 
+LLSettingsBase::ptr_t LLSettingsBase::buildBlend(const ptr_t &begin, const ptr_t &end, F32 blendf)
+{
+    if (begin->getSettingType() != end->getSettingType())
+    {
+        LL_WARNS("SETTINGS") << "Attempt to blend settings of different types! " << 
+            begin->getSettingType() << "<->" << end->getSettingType() << LL_ENDL;
+
+        return LLSettingsBase::ptr_t();
+    }
+
+    return begin->blend(end, blendf);
+}
 
 void LLSettingsBase::exportSettings(std::string name) const
 {
diff --git a/indra/newview/llsettingsbase.h b/indra/newview/llsettingsbase.h
index 02f5ffc8af..f7015fb12b 100644
--- a/indra/newview/llsettingsbase.h
+++ b/indra/newview/llsettingsbase.h
@@ -43,6 +43,7 @@
 class LLSettingsBase: private boost::noncopyable
 {
     friend class LLEnvironment;
+    friend class LLSettingsDayCycle;
 
 public:
     typedef std::map<std::string, S32>  parammapping_t;
@@ -54,6 +55,8 @@ public:
     //---------------------------------------------------------------------
     virtual std::string getSettingType() const = 0;
 
+    static ptr_t buildBlend(const ptr_t &begin, const ptr_t &end, F32 blendf);
+
     //---------------------------------------------------------------------
     // Settings status 
     inline bool hasSetting(const std::string &param) const { return mSettings.has(param); }
@@ -124,8 +127,11 @@ protected:
 
     typedef std::set<std::string>   stringset_t;
 
+    virtual ptr_t blend(const ptr_t &end, F32 blendf) const = 0;
+
     // combining settings objects. Customize for specific setting types
     virtual void lerpSettings(const LLSettingsBase &other, F32 mix);
+    LLSD    interpolateSDMap(const LLSD &settings, const LLSD &other, F32 mix) const;
 
     /// when lerping between settings, some may require special handling.  
     /// Get a list of these key to be skipped by the default settings lerp.
@@ -152,7 +158,6 @@ private:
     bool    mDirty;
 
     LLSD    combineSDMaps(const LLSD &first, const LLSD &other) const;
-    LLSD    interpolateSDMap(const LLSD &settings, const LLSD &other, F32 mix) const;
 
 };
 
diff --git a/indra/newview/llsettingsdaycycle.cpp b/indra/newview/llsettingsdaycycle.cpp
index abf73877ed..bda3c7c138 100644
--- a/indra/newview/llsettingsdaycycle.cpp
+++ b/indra/newview/llsettingsdaycycle.cpp
@@ -42,32 +42,86 @@
 #include "llagent.h"
 #include "pipeline.h"
 
-
 #include "llsettingssky.h"
 #include "llsettingswater.h"
 
+#include "llenvironment.h"
+
 //=========================================================================
 namespace
 {
     LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment");
     LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment");
+
+    inline F32 get_wrapping_distance(F32 begin, F32 end)
+    {
+        return 1.0 - fabs((begin + 1.0) - end);
+    }
+
+    LLSettingsDayCycle::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDayCycle::CycleTrack_t &collection, F32 key)
+    {
+        if (collection.empty())
+            return collection.end();
+
+        LLSettingsDayCycle::CycleTrack_t::iterator it = collection.upper_bound(key);
+
+        if (it == collection.end())
+        {   // wrap around
+            it = collection.begin();
+        }
+
+        return it;
+    }
+
+    LLSettingsDayCycle::CycleTrack_t::iterator get_wrapping_atbefore(LLSettingsDayCycle::CycleTrack_t &collection, F32 key)
+    {
+        if (collection.empty())
+            return collection.end();
+
+        LLSettingsDayCycle::CycleTrack_t::iterator it = collection.lower_bound(key);
+
+        if (it == collection.end())
+        {   // all offsets are lower, take the last one.
+            --it; // we know the range is not empty
+        }
+        else if ((*it).first > key)
+        {   // the offset we are interested in is smaller than the found.
+            if (it == collection.begin())
+                it = collection.end();
+            --it;
+        }
+
+        return it;
+    }
+
+
 }
 
 //=========================================================================
 const std::string LLSettingsDayCycle::SETTING_DAYLENGTH("day_length");
+const std::string LLSettingsDayCycle::SETTING_KEYID("key_id");
+const std::string LLSettingsDayCycle::SETTING_KEYNAME("key_name");
+const std::string LLSettingsDayCycle::SETTING_KEYOFFSET("key_offset");
+const std::string LLSettingsDayCycle::SETTING_NAME("name");
+const std::string LLSettingsDayCycle::SETTING_TRACKS("tracks");
 
 const S32 LLSettingsDayCycle::MINIMUM_DAYLENGTH( 14400); // 4 hours
 const S32 LLSettingsDayCycle::MAXIMUM_DAYLENGTH(604800); // 7 days
 
+const S32 LLSettingsDayCycle::TRACK_WATER(0);   // water track is 0
+const S32 LLSettingsDayCycle::TRACK_MAX(5);     // 5 tracks, 4 skys, 1 water
+
 //=========================================================================
 LLSettingsDayCycle::LLSettingsDayCycle(const LLSD &data) :
     LLSettingsBase(data)
 {
+    mDayTracks.resize(TRACK_MAX);
 }
 
 LLSettingsDayCycle::LLSettingsDayCycle() :
     LLSettingsBase()
 {
+    mDayTracks.resize(TRACK_MAX);
 }
 
 //=========================================================================
@@ -75,18 +129,36 @@ LLSD LLSettingsDayCycle::defaults()
 {
     LLSD dfltsetting;
 
+    dfltsetting[SETTING_NAME] = "_default_";
+    dfltsetting[SETTING_DAYLENGTH] = MINIMUM_DAYLENGTH;
+    dfltsetting[SETTING_TRACKS] = LLSDArray(
+        LLSDArray(LLSDMap(SETTING_KEYOFFSET, LLSD::Real(0.0f))(SETTING_KEYNAME, "_default_"))
+        (LLSDMap(SETTING_KEYOFFSET, LLSD::Real(0.0f))(SETTING_KEYNAME, "_default_")));
     
     return dfltsetting;
 }
 
-
 LLSettingsDayCycle::ptr_t LLSettingsDayCycle::buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings)
 {
     LLSD newsettings(defaults());
 
-    //newsettings[SETTING_NAME] = name;
+    newsettings[SETTING_NAME] = name;
+    newsettings[SETTING_DAYLENGTH] = MINIMUM_DAYLENGTH;
+
+    LLSD watertrack = LLSDArray( 
+        LLSDMap ( SETTING_KEYOFFSET, LLSD::Real(0.0f) )
+                ( SETTING_KEYNAME, "Default" ));
 
+    LLSD skytrack = LLSD::emptyArray();
 
+    for (LLSD::array_const_iterator it = oldsettings.beginArray(); it != oldsettings.endArray(); ++it)
+    {
+        LLSD entry = LLSDMap(SETTING_KEYOFFSET, (*it)[0].asReal())
+            (SETTING_KEYNAME, (*it)[1].asString());
+        skytrack.append(entry);
+    }
+
+    newsettings[SETTING_TRACKS] = LLSDArray(watertrack)(skytrack);
 
     LLSettingsDayCycle::ptr_t dayp = boost::make_shared<LLSettingsDayCycle>(newsettings);
 
@@ -102,6 +174,39 @@ LLSettingsDayCycle::ptr_t LLSettingsDayCycle::buildDefaultDayCycle()
     return dayp;
 }
 
+void LLSettingsDayCycle::parseFromLLSD(LLSD &data)
+{
+    LLEnvironment &environment(LLEnvironment::instance());
+    LLSD tracks = data[SETTING_TRACKS];
+
+    for (S32 i = 0; (i < tracks.size()) && (i < TRACK_MAX); ++i)
+    {
+        mDayTracks[i].clear();
+        LLSD curtrack = tracks[i];
+        for (LLSD::array_const_iterator it = curtrack.beginArray(); it != curtrack.endArray(); ++it)
+        {
+            F32 offset = (*it)[SETTING_KEYOFFSET].asReal();
+            LLSettingsBase::ptr_t setting;
+
+            if ((*it).has(SETTING_KEYNAME))
+            {
+                if (i == TRACK_WATER)
+                    setting = environment.findWaterByName((*it)[SETTING_KEYNAME]);
+                else
+                    setting = environment.findSkyByName((*it)[SETTING_KEYNAME]);
+            }
+            else if ((*it).has(SETTING_KEYID))
+            {
+
+            }
+
+            if (setting)
+                mDayTracks[i][offset] = setting;
+        }
+    }
+}
+
+
 LLSettingsDayCycle::ptr_t LLSettingsDayCycle::buildClone()
 {
     LLSD settings = cloneSettings();
@@ -111,6 +216,12 @@ LLSettingsDayCycle::ptr_t LLSettingsDayCycle::buildClone()
     return dayp;
 }
 
+LLSettingsBase::ptr_t LLSettingsDayCycle::blend(const LLSettingsBase::ptr_t &other, F32 mix) const
+{
+    LL_ERRS("DAYCYCLE") << "Day cycles are not blendable!" << LL_ENDL;
+    return LLSettingsBase::ptr_t();
+}
+
 //=========================================================================
 F32 LLSettingsDayCycle::secondsToOffset(S32 seconds)
 {
@@ -119,6 +230,13 @@ F32 LLSettingsDayCycle::secondsToOffset(S32 seconds)
     return static_cast<F32>(seconds % daylength) / static_cast<F32>(daylength);
 }
 
+S32 LLSettingsDayCycle::offsetToSeconds(F32 offset)
+{
+    S32 daylength = getDayLength();
+
+    return static_cast<S32>(offset * static_cast<F32>(daylength));
+}
+
 //=========================================================================
 void LLSettingsDayCycle::updateSettings()
 {
@@ -133,13 +251,93 @@ void LLSettingsDayCycle::setDayLength(S32 seconds)
     setValue(SETTING_DAYLENGTH, seconds);
 }
 
-void LLSettingsDayCycle::setWaterAt(const LLSettingsSkyPtr_t &water, S32 seconds)
+LLSettingsDayCycle::OffsetList_t LLSettingsDayCycle::getTrackOffsets(S32 trackno)
 {
-//    F32 offset = secondsToOffset(seconds);
+    if ((trackno < 1) || (trackno >= TRACK_MAX))
+    {
+        LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL;
+        return OffsetList_t();
+    }
 
+    OffsetList_t offsets;
+    CycleTrack_t &track = mDayTracks[trackno];
+
+    offsets.reserve(track.size());
+
+    for (CycleTrack_t::iterator it = track.begin(); it != track.end(); ++it)
+    {
+        offsets.push_back((*it).first);
+    }
+
+    return offsets;
+}
+
+LLSettingsDayCycle::TimeList_t LLSettingsDayCycle::getTrackTimes(S32 trackno)
+{
+    OffsetList_t offsets = getTrackOffsets(trackno);
+
+    if (offsets.empty())
+        return TimeList_t();
+
+    TimeList_t times;
+
+    times.reserve(offsets.size());
+    for (OffsetList_t::iterator it = offsets.begin(); it != offsets.end(); ++it)
+    {
+        times.push_back(offsetToSeconds(*it));
+    }
+
+    return times;
+}
+
+void LLSettingsDayCycle::setWaterAtTime(const LLSettingsWaterPtr_t &water, S32 seconds)
+{
+    F32 offset = secondsToOffset(seconds);
+    setWaterAtOffset(water, offset);
+}
+
+void LLSettingsDayCycle::setWaterAtOffset(const LLSettingsWaterPtr_t &water, F32 offset)
+{
+    mDayTracks[TRACK_WATER][offset] = water;
+    setDirtyFlag(true);
 }
 
-void setSkyAtOnTrack(const LLSettingsSkyPtr_t &water, S32 seconds, S32 track)
+
+void LLSettingsDayCycle::setSkyAtOnTrack(const LLSettingsSkyPtr_t &sky, S32 seconds, S32 track)
 {
+    if ((track < 1) || (track >= TRACK_MAX))
+    {
+        LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL;
+        return;
+    }
+    F32 offset = secondsToOffset(seconds);
+
+    mDayTracks[track][offset] = sky;
+    setDirtyFlag(true);
+
+}
 
+LLSettingsDayCycle::TrackBound_t LLSettingsDayCycle::getBoundingEntries(CycleTrack_t &track, F32 offset)
+{
+    return TrackBound_t(get_wrapping_atbefore(track, offset), get_wrapping_atafter(track, offset));
 }
+
+LLSettingsBase::ptr_t LLSettingsDayCycle::getBlendedEntry(CycleTrack_t &track, F32 offset)
+{
+    TrackBound_t bounds = getBoundingEntries(track, offset);
+
+    if (bounds.first == track.end())
+        return LLSettingsBase::ptr_t(); // Track is empty nothing to blend.
+
+    if (bounds.first == bounds.second)
+    {   // Single entry.  Nothing to blend
+        return (*bounds.first).second;
+    }
+
+    F32 blendf = get_wrapping_distance((*bounds.first).first, offset) / get_wrapping_distance((*bounds.first).first, (*bounds.second).first);
+
+    LLSettingsBase::ptr_t base = (*bounds.first).second;
+    return base->blend((*bounds.second).second, blendf);
+}
+
+//=========================================================================
diff --git a/indra/newview/llsettingsdaycycle.h b/indra/newview/llsettingsdaycycle.h
index 9aaa30c24f..5eb704cdb7 100644
--- a/indra/newview/llsettingsdaycycle.h
+++ b/indra/newview/llsettingsdaycycle.h
@@ -40,11 +40,24 @@ class LLSettingsDayCycle : public LLSettingsBase
 {
 public:
     static const std::string    SETTING_DAYLENGTH;
+    static const std::string    SETTING_KEYID;
+    static const std::string    SETTING_KEYNAME;
+    static const std::string    SETTING_KEYOFFSET;
+    static const std::string    SETTING_NAME;
+    static const std::string    SETTING_TRACKS;
 
     static const S32            MINIMUM_DAYLENGTH;
     static const S32            MAXIMUM_DAYLENGTH;
 
-    typedef boost::shared_ptr<LLSettingsDayCycle> ptr_t;
+    static const S32            TRACK_WATER;
+    static const S32            TRACK_MAX;
+
+    typedef std::map<F32, LLSettingsBase::ptr_t>    CycleTrack_t;
+    typedef std::vector<CycleTrack_t>               CycleList_t;
+    typedef boost::shared_ptr<LLSettingsDayCycle>   ptr_t;
+    typedef std::vector<S32>                        TimeList_t;
+    typedef std::vector<F32>                        OffsetList_t;
+    typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator> TrackBound_t;
 
     //---------------------------------------------------------------------
     LLSettingsDayCycle(const LLSD &data);
@@ -58,7 +71,7 @@ public:
     virtual std::string getSettingType() const { return std::string("daycycle"); }
 
     // Settings status 
-    ptr_t blend(const ptr_t &other, F32 mix) const;
+    virtual LLSettingsBase::ptr_t blend(const LLSettingsBase::ptr_t &other, F32 mix) const;
 
     static LLSD defaults();
 
@@ -70,8 +83,14 @@ public:
 
     void setDayLength(S32 seconds);
 
-    void setWaterAt(const LLSettingsSkyPtr_t &water, S32 seconds);
-    void setSkyAtOnTrack(const LLSettingsSkyPtr_t &water, S32 seconds, S32 track);
+    OffsetList_t  getTrackOffsets(S32 track);
+    TimeList_t    getTrackTimes(S32 track);
+
+    void setWaterAtTime(const LLSettingsWaterPtr_t &water, S32 seconds);
+    void setWaterAtOffset(const LLSettingsWaterPtr_t &water, F32 offset);
+    LLSettingsSkyPtr_t getBlendedWaterAt(S32 seconds);
+
+    void setSkyAtOnTrack(const LLSettingsSkyPtr_t &sky, S32 seconds, S32 track);
     //---------------------------------------------------------------------
 
 protected:
@@ -79,13 +98,22 @@ protected:
 
     virtual void        updateSettings();
 
-    typedef std::map<F32, LLSettingsBase::ptr_t>    CycleTrack_t;
-    typedef std::vector<CycleTrack_t>               CycleList_t;
-    typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator> TrackBound_t;
 
     CycleList_t mDayTracks;
 
     F32 secondsToOffset(S32 seconds);
+    S32 offsetToSeconds(F32 offset);
+
+    LLSettingsBase::ptr_t getBlendedEntry(CycleTrack_t &track, F32 offset);
+
+    void parseFromLLSD(LLSD &data);
+//     CycleList_t &           getTrackRef(S32 trackno);
+
+    static CycleTrack_t::iterator   getEntryAtOrBefore(CycleTrack_t &track, F32 offset);
+    static CycleTrack_t::iterator   getEntryAtOrAfter(CycleTrack_t &track, F32 offset);
+
+    static TrackBound_t getBoundingEntries(CycleTrack_t &track, F32 offset);
+
 
 private:
     
diff --git a/indra/newview/llsettingssky.cpp b/indra/newview/llsettingssky.cpp
index c91d4e59ce..782703c7f7 100644
--- a/indra/newview/llsettingssky.cpp
+++ b/indra/newview/llsettingssky.cpp
@@ -103,6 +103,17 @@ LLSettingsSky::LLSettingsSky():
 {
 }
 
+LLSettingsBase::ptr_t LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F32 blendf) const
+{
+    LLSettingsSky::ptr_t other = boost::static_pointer_cast<LLSettingsSky>(end);
+    LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+    LLSettingsSky::ptr_t skyp = boost::make_shared<LLSettingsSky>(blenddata);
+
+    return skyp;
+}
+
+
 void LLSettingsSky::setMoonRotation(F32 azimuth, F32 altitude)
 {
     setValue(SETTING_MOON_ROTATION, ::body_position_from_angles(azimuth, altitude));
diff --git a/indra/newview/llsettingssky.h b/indra/newview/llsettingssky.h
index 8052651030..977ab5141e 100644
--- a/indra/newview/llsettingssky.h
+++ b/indra/newview/llsettingssky.h
@@ -414,6 +414,8 @@ public:
 protected:
     LLSettingsSky();
 
+    virtual LLSettingsBase::ptr_t blend(const LLSettingsBase::ptr_t &end, F32 blendf) const;
+
     virtual stringset_t getSlerpKeys() const;
 
     virtual void        updateSettings();
diff --git a/indra/newview/llsettingswater.cpp b/indra/newview/llsettingswater.cpp
index babaa0b218..52448bd4af 100644
--- a/indra/newview/llsettingswater.cpp
+++ b/indra/newview/llsettingswater.cpp
@@ -195,6 +195,17 @@ LLSettingsWater::ptr_t LLSettingsWater::buildClone()
     return skyp;
 }
 
+LLSettingsBase::ptr_t LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F32 blendf) const
+{
+    LLSettingsWater::ptr_t other = boost::static_pointer_cast<LLSettingsWater>(end);
+    LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+    LLSettingsWater::ptr_t waterp = boost::make_shared<LLSettingsWater>(blenddata);
+
+    return waterp;
+}
+
+
 //=========================================================================
 
 LLSettingsWater::parammapping_t LLSettingsWater::getParameterMap() const
diff --git a/indra/newview/llsettingswater.h b/indra/newview/llsettingswater.h
index d8c9ff5cc6..6a7e692c25 100644
--- a/indra/newview/llsettingswater.h
+++ b/indra/newview/llsettingswater.h
@@ -63,7 +63,7 @@ public:
     virtual std::string getSettingType() const { return std::string("water"); }
 
     // Settings status 
-    ptr_t blend(const ptr_t &other, F32 mix) const;
+    virtual LLSettingsBase::ptr_t blend(const LLSettingsBase::ptr_t &end, F32 blendf) const;
 
     static LLSD defaults();
 
-- 
cgit v1.2.3