summaryrefslogtreecommitdiff
path: root/indra/llinventory
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2017-11-30 11:32:22 -0800
committerRider Linden <rider@lindenlab.com>2017-11-30 11:32:22 -0800
commitd7dd10b88bc3fda88f6528ecc5936e4889f019f3 (patch)
tree50ace17809cc3af599bc991f3ac969ca8748c5ca /indra/llinventory
parente947481d30b51e731947d85de45065d5b0c02e45 (diff)
Split for viewer/simhost sync LLSD with simhost.
Diffstat (limited to 'indra/llinventory')
-rw-r--r--indra/llinventory/CMakeLists.txt8
-rw-r--r--indra/llinventory/llsettingsbase.cpp581
-rw-r--r--indra/llinventory/llsettingsbase.h306
-rw-r--r--indra/llinventory/llsettingsdaycycle.cpp545
-rw-r--r--indra/llinventory/llsettingsdaycycle.h156
-rw-r--r--indra/llinventory/llsettingssky.cpp561
-rw-r--r--indra/llinventory/llsettingssky.h455
-rw-r--r--indra/llinventory/llsettingswater.cpp215
-rw-r--r--indra/llinventory/llsettingswater.h227
9 files changed, 3054 insertions, 0 deletions
diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt
index 68dd00d880..3eba746614 100644
--- a/indra/llinventory/CMakeLists.txt
+++ b/indra/llinventory/CMakeLists.txt
@@ -29,6 +29,10 @@ set(llinventory_SOURCE_FILES
llparcel.cpp
llpermissions.cpp
llsaleinfo.cpp
+ llsettingsbase.cpp
+ llsettingsdaycycle.cpp
+ llsettingssky.cpp
+ llsettingswater.cpp
lltransactionflags.cpp
lluserrelations.cpp
)
@@ -49,6 +53,10 @@ set(llinventory_HEADER_FILES
llpermissions.h
llpermissionsflags.h
llsaleinfo.h
+ llsettingsbase.h
+ llsettingsdaycycle.h
+ llsettingssky.h
+ llsettingswater.h
lltransactionflags.h
lltransactiontypes.h
lluserrelations.h
diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
new file mode 100644
index 0000000000..e4291d8080
--- /dev/null
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -0,0 +1,581 @@
+/**
+* @file llsettingsbase.cpp
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "llsettingsbase.h"
+
+#include "llmath.h"
+#include <algorithm>
+
+#include "llsdserialize.h"
+
+//=========================================================================
+namespace
+{
+ const F32 BREAK_POINT = 0.5;
+}
+
+//=========================================================================
+const std::string LLSettingsBase::SETTING_ID("id");
+const std::string LLSettingsBase::SETTING_NAME("name");
+const std::string LLSettingsBase::SETTING_HASH("hash");
+const std::string LLSettingsBase::SETTING_TYPE("type");
+
+const F32Seconds LLSettingsBlender::DEFAULT_THRESHOLD(0.01);
+
+//=========================================================================
+LLSettingsBase::LLSettingsBase():
+ mSettings(LLSD::emptyMap()),
+ mDirty(true)
+{
+}
+
+LLSettingsBase::LLSettingsBase(const LLSD setting) :
+ mSettings(setting),
+ mDirty(true)
+{
+}
+
+//=========================================================================
+void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F32 mix)
+{
+ mSettings = interpolateSDMap(mSettings, other.mSettings, mix);
+ setDirtyFlag(true);
+}
+
+LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) const
+{
+ LLSD newSettings;
+
+ for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it)
+ {
+ std::string key_name = (*it).first;
+ LLSD value = (*it).second;
+
+ LLSD::Type setting_type = value.type();
+ switch (setting_type)
+ {
+ case LLSD::TypeMap:
+ newSettings[key_name] = combineSDMaps(value, LLSD());
+ break;
+ case LLSD::TypeArray:
+ newSettings[key_name] = LLSD::emptyArray();
+ for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita)
+ {
+ newSettings[key_name].append(*ita);
+ }
+ break;
+ //case LLSD::TypeInteger:
+ //case LLSD::TypeReal:
+ //case LLSD::TypeBoolean:
+ //case LLSD::TypeString:
+ //case LLSD::TypeUUID:
+ //case LLSD::TypeURI:
+ //case LLSD::TypeDate:
+ //case LLSD::TypeBinary:
+ default:
+ newSettings[key_name] = value;
+ break;
+ }
+ }
+
+ if (!other.isUndefined())
+ {
+ for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it)
+ {
+ std::string key_name = (*it).first;
+ LLSD value = (*it).second;
+
+ LLSD::Type setting_type = value.type();
+ switch (setting_type)
+ {
+ case LLSD::TypeMap:
+ newSettings[key_name] = combineSDMaps(value, LLSD());
+ break;
+ case LLSD::TypeArray:
+ newSettings[key_name] = LLSD::emptyArray();
+ for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita)
+ {
+ newSettings[key_name].append(*ita);
+ }
+ break;
+ //case LLSD::TypeInteger:
+ //case LLSD::TypeReal:
+ //case LLSD::TypeBoolean:
+ //case LLSD::TypeString:
+ //case LLSD::TypeUUID:
+ //case LLSD::TypeURI:
+ //case LLSD::TypeDate:
+ //case LLSD::TypeBinary:
+ default:
+ newSettings[key_name] = value;
+ break;
+ }
+ }
+ }
+
+ return newSettings;
+}
+
+LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, F32 mix) const
+{
+ LLSD newSettings;
+
+ stringset_t skip = getSkipInterpolateKeys();
+ stringset_t slerps = getSlerpKeys();
+
+ for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it)
+ {
+ std::string key_name = (*it).first;
+ LLSD value = (*it).second;
+
+ if (skip.find(key_name) != skip.end())
+ continue;
+
+ if (!other.has(key_name))
+ { // The other does not contain this setting, keep the original value
+ // TODO: Should I blend this out instead?
+ newSettings[key_name] = value;
+ continue;
+ }
+ LLSD::Type setting_type = value.type();
+ LLSD other_value = other[key_name];
+
+ if (other_value.type() != setting_type)
+ {
+ // The data type mismatched between this and other. Hard switch when we pass the break point
+ // but issue a warning.
+ LL_WARNS("SETTINGS") << "Setting lerp between mismatched types for '" << key_name << "'." << LL_ENDL;
+ newSettings[key_name] = (mix > BREAK_POINT) ? other_value : value;
+ continue;
+ }
+
+ switch (setting_type)
+ {
+ case LLSD::TypeInteger:
+ // lerp between the two values rounding the result to the nearest integer.
+ newSettings[key_name] = LLSD::Integer(llroundf(lerp(value.asReal(), other_value.asReal(), mix)));
+ break;
+ case LLSD::TypeReal:
+ // lerp between the two values.
+ newSettings[key_name] = LLSD::Real(lerp(value.asReal(), other_value.asReal(), mix));
+ break;
+ case LLSD::TypeMap:
+ // deep copy.
+ newSettings[key_name] = interpolateSDMap(value, other_value, mix);
+ break;
+
+ case LLSD::TypeArray:
+ {
+ LLSD newvalue(LLSD::emptyArray());
+
+ if (slerps.find(key_name) != slerps.end())
+ {
+ LLQuaternion q = slerp(mix, LLQuaternion(value), LLQuaternion(other_value));
+ newvalue = q.getValue();
+ }
+ else
+ { // TODO: We could expand this to inspect the type and do a deep lerp based on type.
+ // for now assume a heterogeneous array of reals.
+ size_t len = std::max(value.size(), other_value.size());
+
+ for (size_t i = 0; i < len; ++i)
+ {
+
+ newvalue[i] = lerp(value[i].asReal(), other_value[i].asReal(), mix);
+ }
+ }
+
+ newSettings[key_name] = newvalue;
+ }
+
+ break;
+
+// case LLSD::TypeBoolean:
+// case LLSD::TypeString:
+// case LLSD::TypeUUID:
+// case LLSD::TypeURI:
+// case LLSD::TypeBinary:
+// case LLSD::TypeDate:
+ default:
+ /* TODO: If the UUID points to an image ID, blend the images. */
+ // atomic or unknown data types. Lerping between them does not make sense so switch at the break.
+ newSettings[key_name] = (mix > BREAK_POINT) ? other_value : value;
+ break;
+ }
+ }
+
+ // Now add anything that is in other but not in the settings
+ for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it)
+ {
+ // TODO: Should I blend this in instead?
+ if (skip.find((*it).first) == skip.end())
+ continue;
+
+ if (!settings.has((*it).first))
+ continue;
+
+ newSettings[(*it).first] = (*it).second;
+ }
+
+ return newSettings;
+}
+
+LLSD LLSettingsBase::getSettings() const
+{
+ return mSettings;
+}
+
+LLSD LLSettingsBase::cloneSettings() const
+{
+ return combineSDMaps(mSettings, LLSD());
+}
+
+size_t LLSettingsBase::getHash() const
+{ // get a shallow copy of the LLSD filtering out values to not include in the hash
+ LLSD hash_settings = llsd_shallow(getSettings(),
+ LLSDMap(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)("*", true));
+
+ return boost::hash<LLSD>{}(hash_settings);
+}
+
+#ifdef VALIDATION_DEBUG
+namespace
+{
+ bool compare_llsd(LLSD valA, LLSD valB)
+ {
+ if (valA.type() != valB.type())
+ return false;
+
+ switch (valA.type())
+ {
+ // case LLSD::TypeMap:
+ // newSettings[key_name] = combineSDMaps(value, LLSD());
+ // break;
+ case LLSD::TypeArray:
+ if (valA.size() != valB.size())
+ return false;
+
+ for (S32 idx = 0; idx < valA.size(); ++idx)
+ {
+ if (!compare_llsd(valA[idx], valB[idx]))
+ return false;
+ }
+ return true;
+
+ case LLSD::TypeInteger:
+ return valA.asInteger() == valB.asInteger();
+
+ case LLSD::TypeReal:
+ return is_approx_equal(valA.asReal(), valB.asReal());
+
+ case LLSD::TypeBoolean:
+ return valA.asBoolean() == valB.asBoolean();
+
+ case LLSD::TypeString:
+ return valA.asString() == valB.asString();
+
+ case LLSD::TypeUUID:
+ return valA.asUUID() == valB.asUUID();
+
+ case LLSD::TypeURI:
+ return valA.asString() == valB.asString();
+
+ case LLSD::TypeDate:
+ return valA.asDate() == valB.asDate();
+ }
+
+ return true;
+ }
+}
+#endif
+
+bool LLSettingsBase::validate()
+{
+ static Validator validateName(SETTING_NAME, false, LLSD::TypeString);
+ static Validator validateId(SETTING_ID, false, LLSD::TypeUUID);
+ static Validator validateHash(SETTING_HASH, false, LLSD::TypeInteger);
+ static Validator validateType(SETTING_TYPE, false, LLSD::TypeString);
+ validation_list_t validations = getValidationList();
+ stringset_t validated;
+ stringset_t strip;
+
+ if (!mSettings.has(SETTING_TYPE))
+ {
+ mSettings[SETTING_TYPE] = getSettingType();
+ }
+
+ // Fields common to all settings.
+ if (!validateName.verify(mSettings))
+ {
+ LL_WARNS("SETTINGS") << "Unable to validate Name." << LL_ENDL;
+ mIsValid = false;
+ return false;
+ }
+ validated.insert(validateName.getName());
+
+ if (!validateId.verify(mSettings))
+ {
+ LL_WARNS("SETTINGS") << "Unable to validate Id." << LL_ENDL;
+ mIsValid = false;
+ return false;
+ }
+ validated.insert(validateId.getName());
+
+ if (!validateHash.verify(mSettings))
+ {
+ LL_WARNS("SETTINGS") << "Unable to validate Hash." << LL_ENDL;
+ mIsValid = false;
+ return false;
+ }
+ validated.insert(validateHash.getName());
+
+ if (!validateType.verify(mSettings))
+ {
+ LL_WARNS("SETTINGS") << "Unable to validate Type." << LL_ENDL;
+ mIsValid = false;
+ return false;
+ }
+ validated.insert(validateType.getName());
+
+ // Fields for specific settings.
+ for (validation_list_t::iterator itv = validations.begin(); itv != validations.end(); ++itv)
+ {
+#ifdef VALIDATION_DEBUG
+ LLSD oldvalue;
+ if (mSettings.has((*itv).getName()))
+ {
+ oldvalue = llsd_clone(mSettings[(*itv).getName()]);
+ }
+#endif
+
+ if (!(*itv).verify(mSettings))
+ {
+ LL_WARNS("SETTINGS") << "Settings LLSD fails validation and could not be corrected for '" << (*itv).getName() << "'!" << LL_ENDL;
+ mIsValid = false;
+ return false;
+ }
+ validated.insert((*itv).getName());
+
+#ifdef VALIDATION_DEBUG
+ if (!oldvalue.isUndefined())
+ {
+ if (!compare_llsd(mSettings[(*itv).getName()], oldvalue))
+ {
+ LL_WARNS("SETTINGS") << "Setting '" << (*itv).getName() << "' was changed: " << oldvalue << " -> " << mSettings[(*itv).getName()] << LL_ENDL;
+ }
+ }
+#endif
+ }
+
+ // strip extra entries
+ for (LLSD::map_iterator itm = mSettings.beginMap(); itm != mSettings.endMap(); ++itm)
+ {
+ if (validated.find((*itm).first) == validated.end())
+ {
+ LL_WARNS("SETTINGS") << "Stripping setting '" << (*itm).first << "'" << LL_ENDL;
+ strip.insert((*itm).first);
+ }
+ }
+
+ for (stringset_t::iterator its = strip.begin(); its != strip.end(); ++its)
+ {
+ mSettings.erase(*its);
+ }
+
+ return true;
+}
+
+//=========================================================================
+bool LLSettingsBase::Validator::verify(LLSD &data)
+{
+ if (!data.has(mName) || (data.has(mName) && data[mName].isUndefined()))
+ {
+ if (mRequired)
+ LL_WARNS("SETTINGS") << "Missing required setting '" << mName << "'" << LL_ENDL;
+ return !mRequired;
+ }
+
+ if (data[mName].type() != mType)
+ {
+ LL_WARNS("SETTINGS") << "Setting '" << mName << "' is incorrect type." << LL_ENDL;
+ return false;
+ }
+
+ if (!mVerify.empty() && !mVerify(data[mName]))
+ {
+ LL_WARNS("SETTINGS") << "Setting '" << mName << "' fails validation." << LL_ENDL;
+ return false;
+ }
+
+ return true;
+}
+
+bool LLSettingsBase::Validator::verifyColor(LLSD &value)
+{
+ return (value.size() == 3 || value.size() == 4);
+}
+
+bool LLSettingsBase::Validator::verifyVector(LLSD &value, S32 length)
+{
+ return (value.size() == length);
+}
+
+bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length)
+{
+ if (value.size() != length)
+ return false;
+
+ LLSD newvector;
+
+ switch (length)
+ {
+ case 2:
+ {
+ LLVector2 vect(value);
+
+ if (is_approx_equal(vect.normalize(), 1.0f))
+ return true;
+ newvector = vect.getValue();
+ break;
+ }
+ case 3:
+ {
+ LLVector3 vect(value);
+
+ if (is_approx_equal(vect.normalize(), 1.0f))
+ return true;
+ newvector = vect.getValue();
+ break;
+ }
+ case 4:
+ {
+ LLVector4 vect(value);
+
+ if (is_approx_equal(vect.normalize(), 1.0f))
+ return true;
+ newvector = vect.getValue();
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals)
+{
+ for (S32 index = 0; index < value.size(); ++index)
+ {
+ if (minvals[index].asString() != "*")
+ {
+ if (minvals[index].asReal() > value[index].asReal())
+ {
+ value[index] = minvals[index].asReal();
+ }
+ }
+ if (maxvals[index].asString() != "*")
+ {
+ if (maxvals[index].asReal() < value[index].asReal())
+ {
+ value[index] = maxvals[index].asReal();
+ }
+ }
+ }
+
+ return true;
+}
+
+bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value)
+{
+ return (value.size() == 4);
+}
+
+bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value)
+{
+ if (value.size() != 4)
+ return false;
+
+ LLQuaternion quat(value);
+
+ if (is_approx_equal(quat.normalize(), 1.0f))
+ return true;
+
+ LLSD newquat = quat.getValue();
+ for (S32 index = 0; index < 4; ++index)
+ {
+ value[index] = newquat[index];
+ }
+ return true;
+}
+
+bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range)
+{
+ F32 real = value.asReal();
+
+ F32 clampedval = llclamp(LLSD::Real(real), range[0].asReal(), range[1].asReal());
+
+ if (is_approx_equal(clampedval, real))
+ return true;
+
+ value = LLSD::Real(clampedval);
+ return true;
+}
+
+bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range)
+{
+ S32 ival = value.asInteger();
+
+ S32 clampedval = llclamp(LLSD::Integer(ival), range[0].asInteger(), range[1].asInteger());
+
+ if (clampedval == ival)
+ return true;
+
+ value = LLSD::Integer(clampedval);
+ return true;
+}
+
+//=========================================================================
+
+void LLSettingsBlender::update(F32Seconds timedelta)
+{
+ mTimeSpent += timedelta;
+
+ if (mTimeSpent >= mSeconds)
+ {
+ LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon
+ mOnFinished(shared_from_this());
+ mOnFinished.disconnect_all_slots(); // prevent from firing more than once.
+ return;
+ }
+
+ F32 blendf = fmod(mTimeSpent.value(), mSeconds.value()) / mSeconds.value();
+
+ mTarget->replaceSettings(mInitial->getSettings());
+ mTarget->blend(mFinal, blendf);
+}
+
diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h
new file mode 100644
index 0000000000..2b59a103ad
--- /dev/null
+++ b/indra/llinventory/llsettingsbase.h
@@ -0,0 +1,306 @@
+/**
+* @file llsettingsbase.h
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SETTINGS_BASE_H
+#define LL_SETTINGS_BASE_H
+
+#include <string>
+#include <map>
+#include <vector>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/signals2.hpp>
+
+#include "llsd.h"
+#include "llsdutil.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "llquaternion.h"
+#include "v4color.h"
+#include "v3color.h"
+
+class LLSettingsBase :
+ public boost::enable_shared_from_this<LLSettingsBase>,
+ private boost::noncopyable
+{
+ friend class LLEnvironment;
+ friend class LLSettingsDay;
+
+public:
+ static const std::string SETTING_ID;
+ static const std::string SETTING_NAME;
+ static const std::string SETTING_HASH;
+ static const std::string SETTING_TYPE;
+
+ typedef std::map<std::string, S32> parammapping_t;
+
+ typedef boost::shared_ptr<LLSettingsBase> ptr_t;
+
+ virtual ~LLSettingsBase() { };
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const = 0;
+
+ //---------------------------------------------------------------------
+ // Settings status
+ inline bool hasSetting(const std::string &param) const { return mSettings.has(param); }
+ inline bool isDirty() const { return mDirty; }
+ inline void setDirtyFlag(bool dirty) { mDirty = dirty; }
+
+ size_t getHash() const; // Hash will not include Name, ID or a previously stored Hash
+
+ inline LLUUID getId() const
+ {
+ return getValue(SETTING_ID).asUUID();
+ }
+
+ inline std::string getName() const
+ {
+ return getValue(SETTING_NAME).asString();
+ }
+
+ inline void setName(std::string val)
+ {
+ setValue(SETTING_NAME, val);
+ }
+
+ inline void replaceSettings(LLSD settings)
+ {
+ mSettings = settings;
+ setDirtyFlag(true);
+ }
+
+ virtual LLSD getSettings() const;
+
+ //---------------------------------------------------------------------
+ //
+ inline void setValue(const std::string &name, const LLSD &value)
+ {
+ mSettings[name] = value;
+ mDirty = true;
+ }
+
+ inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD()) const
+ {
+ if (!mSettings.has(name))
+ return deflt;
+ return mSettings[name];
+ }
+
+ inline void setValue(const std::string &name, const LLVector2 &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ inline void setValue(const std::string &name, const LLVector3 &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ inline void setValue(const std::string &name, const LLVector4 &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ inline void setValue(const std::string &name, const LLQuaternion &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ inline void setValue(const std::string &name, const LLColor3 &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ inline void setValue(const std::string &name, const LLColor4 &value)
+ {
+ setValue(name, value.getValue());
+ }
+
+ // Note this method is marked const but may modify the settings object.
+ // (note the internal const cast). This is so that it may be called without
+ // special consideration from getters.
+ inline void update() const
+ {
+ if (!mDirty)
+ return;
+ (const_cast<LLSettingsBase *>(this))->updateSettings();
+ }
+
+ virtual void blend(const ptr_t &end, F32 blendf) = 0;
+
+ virtual bool validate();
+
+protected:
+ class Validator
+ {
+ public:
+ typedef boost::function<bool(LLSD &)> verify_pr;
+
+ Validator(std::string name, bool required, LLSD::Type type, verify_pr verify = verify_pr()) :
+ mName(name),
+ mRequired(required),
+ mType(type),
+ mVerify(verify)
+ { }
+
+ std::string getName() const { return mName; }
+ bool isRequired() const { return mRequired; }
+ LLSD::Type getType() const { return mType; }
+
+ bool verify(LLSD &data);
+
+ // Some basic verifications
+ static bool verifyColor(LLSD &value);
+ static bool verifyVector(LLSD &value, S32 length);
+ static bool verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals);
+ static bool verifyVectorNormalized(LLSD &value, S32 length);
+ static bool verifyQuaternion(LLSD &value);
+ static bool verifyQuaternionNormal(LLSD &value);
+ static bool verifyFloatRange(LLSD &value, LLSD range);
+ static bool verifyIntegerRange(LLSD &value, LLSD range);
+
+ private:
+ std::string mName;
+ bool mRequired;
+ LLSD::Type mType;
+ verify_pr mVerify;
+ };
+ typedef std::vector<Validator> validation_list_t;
+
+ LLSettingsBase();
+ LLSettingsBase(const LLSD setting);
+
+ typedef std::set<std::string> stringset_t;
+
+ // 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.
+ /// (handling should be performed in the override of lerpSettings.
+ virtual stringset_t getSkipInterpolateKeys() const { return stringset_t(); }
+
+ // A list of settings that represent quaternions and should be slerped
+ // rather than lerped.
+ virtual stringset_t getSlerpKeys() const { return stringset_t(); }
+
+ // Calculate any custom settings that may need to be cached.
+ virtual void updateSettings() { mDirty = false; };
+
+ virtual validation_list_t getValidationList() const = 0;
+
+ // Apply any settings that need special handling.
+ virtual void applySpecial(void *) { };
+
+ virtual parammapping_t getParameterMap() const { return parammapping_t(); }
+
+ LLSD mSettings;
+ bool mIsValid;
+
+ LLSD cloneSettings() const;
+
+private:
+ bool mDirty;
+
+ LLSD combineSDMaps(const LLSD &first, const LLSD &other) const;
+
+};
+
+
+class LLSettingsBlender : public boost::enable_shared_from_this<LLSettingsBlender>
+{
+public:
+ typedef boost::shared_ptr<LLSettingsBlender> ptr_t;
+ typedef boost::signals2::signal<void(const ptr_t &)> finish_signal_t;
+ typedef boost::signals2::connection connection_t;
+
+ static const F32Seconds DEFAULT_THRESHOLD;
+
+ LLSettingsBlender(const LLSettingsBase::ptr_t &target,
+ const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, F32Seconds seconds) :
+ mTarget(target),
+ mInitial(initsetting),
+ mFinal(endsetting),
+ mSeconds(seconds),
+ mOnFinished(),
+ mBlendThreshold(DEFAULT_THRESHOLD),
+ mLastUpdate(0.0f),
+ mTimeSpent(0.0f)
+ {
+ mTarget->replaceSettings(mInitial->getSettings());
+ mTimeStart = F32Seconds(LLDate::now().secondsSinceEpoch());
+ mLastUpdate = mTimeStart;
+ }
+
+ ~LLSettingsBlender() {}
+
+ connection_t setOnFinished(const finish_signal_t::slot_type &onfinished)
+ {
+ return mOnFinished.connect(onfinished);
+ }
+
+ void setUpdateThreshold(F32Seconds threshold)
+ {
+ mBlendThreshold = threshold;
+ }
+
+ F32Seconds getUpdateThreshold() const
+ {
+ return mBlendThreshold;
+ }
+
+ LLSettingsBase::ptr_t getTarget() const
+ {
+ return mTarget;
+ }
+
+ LLSettingsBase::ptr_t getInitial() const
+ {
+ return mInitial;
+ }
+
+ LLSettingsBase::ptr_t getFinal() const
+ {
+ return mFinal;
+ }
+
+ void update(F32Seconds time);
+private:
+ LLSettingsBase::ptr_t mTarget;
+ LLSettingsBase::ptr_t mInitial;
+ LLSettingsBase::ptr_t mFinal;
+ F32Seconds mSeconds;
+ finish_signal_t mOnFinished;
+ F32Seconds mBlendThreshold;
+ F32Seconds mLastUpdate;
+ F32Seconds mTimeSpent;
+ F32Seconds mTimeStart;
+};
+
+#endif
diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp
new file mode 100644
index 0000000000..687210e127
--- /dev/null
+++ b/indra/llinventory/llsettingsdaycycle.cpp
@@ -0,0 +1,545 @@
+/**
+* @file llsettingsdaycycle.cpp
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "llsettingsdaycycle.h"
+#include <algorithm>
+#include <boost/make_shared.hpp>
+#include "lltrace.h"
+#include "llfasttimer.h"
+#include "v3colorutil.h"
+
+#include "llsettingssky.h"
+#include "llsettingswater.h"
+
+#include "llframetimer.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)
+ {
+ if (begin < end)
+ {
+ return end - begin;
+ }
+ else if (begin > end)
+ {
+ return 1.0 - (begin - end);
+ }
+
+ return 0;
+ }
+
+ LLSettingsDay::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDay::CycleTrack_t &collection, F32 key)
+ {
+ if (collection.empty())
+ return collection.end();
+
+ LLSettingsDay::CycleTrack_t::iterator it = collection.upper_bound(key);
+
+ if (it == collection.end())
+ { // wrap around
+ it = collection.begin();
+ }
+
+ return it;
+ }
+
+ LLSettingsDay::CycleTrack_t::iterator get_wrapping_atbefore(LLSettingsDay::CycleTrack_t &collection, F32 key)
+ {
+ if (collection.empty())
+ return collection.end();
+
+ LLSettingsDay::CycleTrack_t::iterator it = collection.lower_bound(key);
+
+ if (it == collection.end())
+ { // all keyframes are lower, take the last one.
+ --it; // we know the range is not empty
+ }
+ else if ((*it).first > key)
+ { // the keyframe we are interested in is smaller than the found.
+ if (it == collection.begin())
+ it = collection.end();
+ --it;
+ }
+
+ return it;
+ }
+
+
+}
+
+//=========================================================================
+const std::string LLSettingsDay::SETTING_DAYLENGTH("day_length");
+const std::string LLSettingsDay::SETTING_KEYID("key_id");
+const std::string LLSettingsDay::SETTING_KEYNAME("key_name");
+const std::string LLSettingsDay::SETTING_KEYKFRAME("key_keyframe");
+const std::string LLSettingsDay::SETTING_KEYHASH("key_hash");
+const std::string LLSettingsDay::SETTING_TRACKS("tracks");
+const std::string LLSettingsDay::SETTING_FRAMES("frames");
+
+const S64 LLSettingsDay::MINIMUM_DAYLENGTH( 300); // 5 mins
+
+//const S64 LLSettingsDay::MINIMUM_DAYLENGTH( 14400); // 4 hours
+const S64 LLSettingsDay::MAXIMUM_DAYLENGTH(604800); // 7 days
+
+const S32 LLSettingsDay::TRACK_WATER(0); // water track is 0
+const S32 LLSettingsDay::TRACK_MAX(5); // 5 tracks, 4 skys, 1 water
+const S32 LLSettingsDay::FRAME_MAX(56);
+
+//=========================================================================
+LLSettingsDay::LLSettingsDay(const LLSD &data) :
+ LLSettingsBase(data),
+ mInitialized(false)
+{
+ mDayTracks.resize(TRACK_MAX);
+}
+
+LLSettingsDay::LLSettingsDay() :
+ LLSettingsBase(),
+ mInitialized(false)
+{
+ mDayTracks.resize(TRACK_MAX);
+}
+
+//=========================================================================
+LLSD LLSettingsDay::getSettings() const
+{
+ LLSD settings(LLSD::emptyMap());
+
+ if (mSettings.has(SETTING_NAME))
+ settings[SETTING_NAME] = mSettings[SETTING_NAME];
+
+ if (mSettings.has(SETTING_ID))
+ settings[SETTING_ID] = mSettings[SETTING_ID];
+
+ std::map<std::string, LLSettingsBase::ptr_t> in_use;
+
+ LLSD tracks(LLSD::emptyArray());
+
+ for (CycleList_t::const_iterator itTrack = mDayTracks.begin(); itTrack != mDayTracks.end(); ++itTrack)
+ {
+ LLSD trackout(LLSD::emptyArray());
+
+ for (CycleTrack_t::const_iterator itFrame = (*itTrack).begin(); itFrame != (*itTrack).end(); ++itFrame)
+ {
+ F32 frame = (*itFrame).first;
+ LLSettingsBase::ptr_t data = (*itFrame).second;
+ size_t datahash = data->getHash();
+
+ std::stringstream keyname;
+ keyname << datahash;
+
+ trackout.append(LLSD(LLSDMap(SETTING_KEYKFRAME, LLSD::Real(frame))(SETTING_KEYNAME, keyname.str())));
+ in_use[keyname.str()] = data;
+ }
+ tracks.append(trackout);
+ }
+ settings[SETTING_TRACKS] = tracks;
+
+ LLSD frames(LLSD::emptyMap());
+ for (std::map<std::string, LLSettingsBase::ptr_t>::iterator itFrame = in_use.begin(); itFrame != in_use.end(); ++itFrame)
+ {
+ LLSD framesettings = llsd_clone((*itFrame).second->getSettings(),
+ LLSDMap("*", true)(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false));
+
+ frames[(*itFrame).first] = framesettings;
+ }
+ settings[SETTING_FRAMES] = frames;
+
+ return settings;
+}
+
+void LLSettingsDay::initialize()
+{
+ LLSD tracks = mSettings[SETTING_TRACKS];
+ LLSD frames = mSettings[SETTING_FRAMES];
+
+ std::map<std::string, LLSettingsBase::ptr_t> used;
+
+ for (LLSD::map_const_iterator itFrame = frames.beginMap(); itFrame != frames.endMap(); ++itFrame)
+ {
+ std::string name = (*itFrame).first;
+ LLSD data = (*itFrame).second;
+
+ if (data[SETTING_TYPE].asString() == "sky")
+ {
+ used[name] = buildSky(data);
+ }
+ else if (data[SETTING_TYPE].asString() == "water")
+ {
+ used[name] = buildWater(data);
+ }
+ else
+ {
+ LL_WARNS("DAYCYCLE") << "Unknown child setting type '" << data[SETTING_TYPE].asString() << "' named '" << name << "'" << LL_ENDL;
+ }
+ }
+
+ 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 keyframe = (*it)[SETTING_KEYKFRAME].asReal();
+ keyframe = llclamp(keyframe, 0.0f, 1.0f);
+ LLSettingsBase::ptr_t setting;
+
+ if ((*it).has(SETTING_KEYNAME))
+ {
+ if (i == TRACK_WATER)
+ {
+ setting = used[(*it)[SETTING_KEYNAME]];
+ if (!setting)
+ setting = getNamedWater((*it)[SETTING_KEYNAME]);
+ if (setting && setting->getSettingType() != "water")
+ {
+ LL_WARNS("DAYCYCLE") << "Water track referencing " << setting->getSettingType() << " frame at " << keyframe << "." << LL_ENDL;
+ setting.reset();
+ }
+ }
+ else
+ {
+ setting = used[(*it)[SETTING_KEYNAME]];
+ if (!setting)
+ setting = getNamedSky((*it)[SETTING_KEYNAME]);
+ if (setting && setting->getSettingType() != "sky")
+ {
+ LL_WARNS("DAYCYCLE") << "Sky track #" << i << " referencing " << setting->getSettingType() << " frame at " << keyframe << "." << LL_ENDL;
+ setting.reset();
+ }
+ }
+ }
+
+ if (setting)
+ mDayTracks[i][keyframe] = setting;
+ }
+ }
+
+ // these are no longer needed and just take up space now.
+ mSettings.erase(SETTING_TRACKS);
+ mSettings.erase(SETTING_FRAMES);
+
+ mInitialized = true;
+}
+
+
+//=========================================================================
+LLSD LLSettingsDay::defaults()
+{
+ LLSD dfltsetting;
+
+ dfltsetting[SETTING_NAME] = "_default_";
+ dfltsetting[SETTING_DAYLENGTH] = static_cast<S32>(MINIMUM_DAYLENGTH);
+ dfltsetting[SETTING_TRACKS] = LLSDArray(
+ LLSDArray(LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))(SETTING_KEYNAME, "_default_"))
+ (LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))(SETTING_KEYNAME, "_default_")));
+ dfltsetting[SETTING_FRAMES] = LLSD::emptyMap();
+
+ return dfltsetting;
+}
+
+void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F32 mix)
+{
+ LL_ERRS("DAYCYCLE") << "Day cycles are not blendable!" << LL_ENDL;
+}
+
+namespace
+{
+ bool validateDayCycleTrack(LLSD &value)
+ {
+ // Trim extra tracks.
+ while (value.size() > LLSettingsDay::TRACK_MAX)
+ {
+ value.erase(value.size() - 1);
+ }
+
+ for (LLSD::array_iterator track = value.beginArray(); track != value.endArray(); ++track)
+ {
+ S32 index = 0;
+ while (index < (*track).size())
+ {
+ if (index >= LLSettingsDay::FRAME_MAX)
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ if (!(*track)[index].has(LLSettingsDay::SETTING_KEYKFRAME) ||
+ !(*track)[index][LLSettingsDay::SETTING_KEYKFRAME].isReal())
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ if (!(*track)[index].has(LLSettingsDay::SETTING_KEYNAME) &&
+ !(*track)[index].has(LLSettingsDay::SETTING_KEYID))
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ F32 frame = (*track)[index][LLSettingsDay::SETTING_KEYKFRAME].asReal();
+ if ((frame < 0.0) || (frame > 1.0))
+ {
+ frame = llclamp(frame, 0.0f, 1.0f);
+ (*track)[index][LLSettingsDay::SETTING_KEYKFRAME] = frame;
+ }
+ ++index;
+ }
+
+ }
+ return true;
+ }
+}
+
+LLSettingsDay::validation_list_t LLSettingsDay::getValidationList() const
+{
+ static validation_list_t validation;
+
+ if (validation.empty())
+ {
+ validation.push_back(Validator(SETTING_TRACKS, false, LLSD::TypeArray,
+ &validateDayCycleTrack));
+ validation.push_back(Validator(SETTING_FRAMES, false, LLSD::TypeMap));
+ validation.push_back(Validator(SETTING_DAYLENGTH, false, LLSD::TypeInteger,
+ boost::bind(&Validator::verifyIntegerRange, _1,
+ LLSD(LLSDArray(LLSD::Integer(MINIMUM_DAYLENGTH))(LLSD::Integer(MAXIMUM_DAYLENGTH))))));
+ }
+
+ return validation;
+}
+
+//=========================================================================
+F32 LLSettingsDay::secondsToKeyframe(S64Seconds seconds)
+{
+ S64Seconds daylength = getDayLength();
+
+ return llclamp(static_cast<F32>(seconds.value() % daylength.value()) / static_cast<F32>(daylength.value()), 0.0f, 1.0f);
+}
+
+F64Seconds LLSettingsDay::keyframeToSeconds(F32 keyframe)
+{
+ S64Seconds daylength = getDayLength();
+
+ return F64Seconds(static_cast<S32>(keyframe * static_cast<F32>(daylength.value())));
+}
+
+//=========================================================================
+void LLSettingsDay::startDayCycle()
+{
+ F64Seconds now(LLDate::now().secondsSinceEpoch());
+
+ if (!mInitialized)
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to start day cycle on uninitialized object." << LL_ENDL;
+ return;
+ }
+
+ // water
+ if (mDayTracks[0].empty())
+ {
+ mBlendedWater.reset();
+ mWaterBlender.reset();
+ }
+ else if (mDayTracks[0].size() == 1)
+ {
+ mBlendedWater = boost::static_pointer_cast<LLSettingsWater>((*(mDayTracks[0].begin())).second);
+ mWaterBlender.reset();
+ }
+ else
+ {
+ TrackBound_t bounds = getBoundingEntries(mDayTracks[0], now);
+
+ F64Seconds timespan = F64Seconds( getDayLength() * get_wrapping_distance((*bounds.first).first, (*bounds.second).first));
+
+ mBlendedWater = getDefaultWater();
+ mWaterBlender = boost::make_shared<LLSettingsBlender>(mBlendedWater,
+ (*bounds.first).second, (*bounds.second).second, timespan);
+ mWaterBlender->setOnFinished(boost::bind(&LLSettingsDay::onWaterTransitionDone, this, _1));
+ }
+
+ // sky
+ if (mDayTracks[1].empty())
+ {
+ mBlendedSky.reset();
+ mSkyBlender.reset();
+ }
+ else if (mDayTracks[1].size() == 1)
+ {
+ mBlendedSky = boost::static_pointer_cast<LLSettingsSky>( (*(mDayTracks[1].begin())).second);
+ mSkyBlender.reset();
+ }
+ else
+ {
+ TrackBound_t bounds = getBoundingEntries(mDayTracks[1], now);
+ F64Seconds timespan = F64Seconds(getDayLength() * get_wrapping_distance((*bounds.first).first, (*bounds.second).first));
+
+ mBlendedSky = getDefaultSky();
+ mSkyBlender = boost::make_shared<LLSettingsBlender>(mBlendedSky,
+ (*bounds.first).second, (*bounds.second).second, timespan);
+ mSkyBlender->setOnFinished(boost::bind(&LLSettingsDay::onSkyTransitionDone, this, 1, _1));
+ }
+}
+
+
+void LLSettingsDay::updateSettings()
+{
+ static LLFrameTimer timer;
+
+
+ F64Seconds delta(timer.getElapsedTimeAndResetF32());
+
+ if (mSkyBlender)
+ mSkyBlender->update(delta);
+ if (mWaterBlender)
+ mWaterBlender->update(delta);
+}
+
+//=========================================================================
+void LLSettingsDay::setDayLength(S64Seconds seconds)
+{
+ S32 val = llclamp(seconds.value(), MINIMUM_DAYLENGTH, MAXIMUM_DAYLENGTH);
+
+ setValue(SETTING_DAYLENGTH, val);
+}
+
+LLSettingsDay::KeyframeList_t LLSettingsDay::getTrackKeyframes(S32 trackno)
+{
+ if ((trackno < 1) || (trackno >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL;
+ return KeyframeList_t();
+ }
+
+ KeyframeList_t keyframes;
+ CycleTrack_t &track = mDayTracks[trackno];
+
+ keyframes.reserve(track.size());
+
+ for (CycleTrack_t::iterator it = track.begin(); it != track.end(); ++it)
+ {
+ keyframes.push_back((*it).first);
+ }
+
+ return keyframes;
+}
+
+LLSettingsDay::TimeList_t LLSettingsDay::getTrackTimes(S32 trackno)
+{
+ KeyframeList_t keyframes = getTrackKeyframes(trackno);
+
+ if (keyframes.empty())
+ return TimeList_t();
+
+ TimeList_t times;
+
+ times.reserve(keyframes.size());
+ for (KeyframeList_t::iterator it = keyframes.begin(); it != keyframes.end(); ++it)
+ {
+ times.push_back(keyframeToSeconds(*it));
+ }
+
+ return times;
+}
+
+void LLSettingsDay::setWaterAtTime(const LLSettingsWaterPtr_t &water, S64Seconds seconds)
+{
+ F32 keyframe = secondsToKeyframe(seconds);
+ setWaterAtKeyframe(water, keyframe);
+}
+
+void LLSettingsDay::setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, F32 keyframe)
+{
+ mDayTracks[TRACK_WATER][llclamp(keyframe, 0.0f, 1.0f)] = water;
+ setDirtyFlag(true);
+}
+
+
+void LLSettingsDay::setSkyAtTime(const LLSettingsSkyPtr_t &sky, S64Seconds seconds, S32 track)
+{
+ F32 keyframe = secondsToKeyframe(seconds);
+ setSkyAtKeyframe(sky, keyframe, track);
+}
+
+void LLSettingsDay::setSkyAtKeyframe(const LLSettingsSkyPtr_t &sky, F32 keyframe, S32 track)
+{
+ if ((track < 1) || (track >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL;
+ return;
+ }
+
+ mDayTracks[track][llclamp(keyframe, 0.0f, 1.0f)] = sky;
+ setDirtyFlag(true);
+}
+
+LLSettingsDay::TrackBound_t LLSettingsDay::getBoundingEntries(LLSettingsDay::CycleTrack_t &track, F32 keyframe)
+{
+ return TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe));
+}
+
+LLSettingsDay::TrackBound_t LLSettingsDay::getBoundingEntries(LLSettingsDay::CycleTrack_t &track, F64Seconds time)
+{
+ F32 frame = secondsToKeyframe(time);
+
+ return getBoundingEntries(track, frame);
+}
+
+//=========================================================================
+void LLSettingsDay::onSkyTransitionDone(S32 track, const LLSettingsBlender::ptr_t &blender)
+{
+ F64Seconds now(LLDate::now().secondsSinceEpoch());
+ TrackBound_t bounds = getBoundingEntries(mDayTracks[track], now);
+
+ F32 distance = get_wrapping_distance((*bounds.first).first, (*bounds.second).first);
+ F64Seconds timespan = F64Seconds(distance * getDayLength());
+
+ LL_DEBUGS("DAYCYCLE") << "New sky blender. now=" << now <<
+ " start=" << (*bounds.first).first << " end=" << (*bounds.second).first <<
+ " span=" << timespan << LL_ENDL;
+
+ mSkyBlender = boost::make_shared<LLSettingsBlender>(mBlendedSky,
+ (*bounds.first).second, (*bounds.second).second, timespan);
+ mSkyBlender->setOnFinished(boost::bind(&LLSettingsDay::onSkyTransitionDone, this, track, _1));
+}
+
+void LLSettingsDay::onWaterTransitionDone(const LLSettingsBlender::ptr_t &blender)
+{
+ F64Seconds now(LLDate::now().secondsSinceEpoch());
+ TrackBound_t bounds = getBoundingEntries(mDayTracks[0], now);
+
+ F32 distance = get_wrapping_distance((*bounds.first).first, (*bounds.second).first);
+ F64Seconds timespan = F64Seconds(distance * getDayLength());
+
+ mWaterBlender = boost::make_shared<LLSettingsBlender>(mBlendedWater,
+ (*bounds.first).second, (*bounds.second).second, timespan);
+ mWaterBlender->setOnFinished(boost::bind(&LLSettingsDay::onWaterTransitionDone, this, _1));
+}
diff --git a/indra/llinventory/llsettingsdaycycle.h b/indra/llinventory/llsettingsdaycycle.h
new file mode 100644
index 0000000000..3b24ce9f97
--- /dev/null
+++ b/indra/llinventory/llsettingsdaycycle.h
@@ -0,0 +1,156 @@
+/**
+* @file llsettingsdaycycle.h
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SETTINGS_DAYCYCLE_H
+#define LL_SETTINGS_DAYCYCLE_H
+
+#include "llsettingsbase.h"
+
+class LLSettingsWater;
+class LLSettingsSky;
+
+typedef boost::shared_ptr<LLSettingsWater> LLSettingsWaterPtr_t;
+typedef boost::shared_ptr<LLSettingsSky> LLSettingsSkyPtr_t;
+
+class LLSettingsDay : 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_KEYKFRAME;
+ static const std::string SETTING_KEYHASH;
+ static const std::string SETTING_TRACKS;
+ static const std::string SETTING_FRAMES;
+
+ static const S64 MINIMUM_DAYLENGTH;
+ static const S64 MAXIMUM_DAYLENGTH;
+
+ static const S32 TRACK_WATER;
+ static const S32 TRACK_MAX;
+ static const S32 FRAME_MAX;
+
+ typedef std::map<F32, LLSettingsBase::ptr_t> CycleTrack_t;
+ typedef std::vector<CycleTrack_t> CycleList_t;
+ typedef boost::shared_ptr<LLSettingsDay> ptr_t;
+ typedef std::vector<S64Seconds> TimeList_t;
+ typedef std::vector<F32> KeyframeList_t;
+ typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator> TrackBound_t;
+
+ //---------------------------------------------------------------------
+ LLSettingsDay(const LLSD &data);
+ virtual ~LLSettingsDay() { };
+
+ void initialize();
+
+ virtual ptr_t buildClone() = 0;
+ virtual LLSD getSettings() const;
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const { return std::string("daycycle"); }
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &other, F32 mix);
+
+ static LLSD defaults();
+
+ //---------------------------------------------------------------------
+ S64Seconds getDayLength() const
+ {
+ return S64Seconds(mSettings[SETTING_DAYLENGTH].asInteger());
+ }
+
+ void setDayLength(S64Seconds seconds);
+
+ KeyframeList_t getTrackKeyframes(S32 track);
+ TimeList_t getTrackTimes(S32 track);
+
+ void setWaterAtTime(const LLSettingsWaterPtr_t &water, S64Seconds seconds);
+ void setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, F32 keyframe);
+
+ void setSkyAtTime(const LLSettingsSkyPtr_t &sky, S64Seconds seconds, S32 track);
+ void setSkyAtKeyframe(const LLSettingsSkyPtr_t &sky, F32 keyframe, S32 track);
+ //---------------------------------------------------------------------
+ void startDayCycle();
+
+ LLSettingsSkyPtr_t getCurrentSky() const
+ {
+ return mBlendedSky;
+ }
+
+ LLSettingsWaterPtr_t getCurrentWater() const
+ {
+ return mBlendedWater;
+ }
+
+ virtual LLSettingsSkyPtr_t getDefaultSky() const = 0;
+ virtual LLSettingsWaterPtr_t getDefaultWater() const = 0;
+
+ virtual LLSettingsSkyPtr_t buildSky(LLSD) const = 0;
+ virtual LLSettingsWaterPtr_t buildWater(LLSD) const = 0;
+
+ virtual LLSettingsSkyPtr_t getNamedSky(const std::string &) const = 0;
+ virtual LLSettingsWaterPtr_t getNamedWater(const std::string &) const = 0;
+
+ void setInitialized(bool value = true) { mInitialized = value; }
+protected:
+ LLSettingsDay();
+
+ virtual void updateSettings();
+
+ virtual validation_list_t getValidationList() const;
+
+ bool mInitialized;
+
+private:
+ LLSettingsBlender::ptr_t mSkyBlender; // convert to [] for altitudes
+ LLSettingsBlender::ptr_t mWaterBlender;
+
+ LLSettingsSkyPtr_t mBlendedSky;
+ LLSettingsWaterPtr_t mBlendedWater;
+
+ CycleList_t mDayTracks;
+
+ F64Seconds mLastUpdateTime;
+
+ F32 secondsToKeyframe(S64Seconds seconds);
+ F64Seconds keyframeToSeconds(F32 keyframe);
+
+ void parseFromLLSD(LLSD &data);
+
+ static CycleTrack_t::iterator getEntryAtOrBefore(CycleTrack_t &track, F32 keyframe);
+ static CycleTrack_t::iterator getEntryAtOrAfter(CycleTrack_t &track, F32 keyframe);
+
+ TrackBound_t getBoundingEntries(CycleTrack_t &track, F32 keyframe);
+ TrackBound_t getBoundingEntries(CycleTrack_t &track, F64Seconds time);
+
+ void onSkyTransitionDone(S32 track, const LLSettingsBlender::ptr_t &blender);
+ void onWaterTransitionDone(const LLSettingsBlender::ptr_t &blender);
+
+};
+
+#endif
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
new file mode 100644
index 0000000000..ecc89165e8
--- /dev/null
+++ b/indra/llinventory/llsettingssky.cpp
@@ -0,0 +1,561 @@
+/**
+* @file llsettingssky.cpp
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "llsettingssky.h"
+#include "indra_constants.h"
+#include <algorithm>
+#include "lltrace.h"
+#include "llfasttimer.h"
+#include "v3colorutil.h"
+
+//=========================================================================
+namespace
+{
+ const LLVector3 DUE_EAST(0.0f, 0.0f, 1.0);
+ const LLVector3 VECT_ZENITH(0.f, 1.f, 0.f);
+ const LLVector3 VECT_NORTHSOUTH(1.f, 0.f, 0.f);
+
+ LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment");
+ LLTrace::BlockTimerStatHandle FTM_UPDATE_SKYVALUES("Update Sky Environment");
+
+ LLQuaternion body_position_from_angles(F32 azimuth, F32 altitude);
+ void angles_from_rotation(LLQuaternion quat, F32 &azimuth, F32 &altitude);
+}
+
+const F32 LLSettingsSky::DOME_OFFSET(0.96f);
+const F32 LLSettingsSky::DOME_RADIUS(15000.f);
+
+const F32 LLSettingsSky::NIGHTTIME_ELEVATION(-8.0f); // degrees
+const F32 LLSettingsSky::NIGHTTIME_ELEVATION_COS((F32)sin(NIGHTTIME_ELEVATION*DEG_TO_RAD));
+
+//=========================================================================
+const std::string LLSettingsSky::SETTING_AMBIENT("ambient");
+const std::string LLSettingsSky::SETTING_BLOOM_TEXTUREID("bloom_id");
+const std::string LLSettingsSky::SETTING_BLUE_DENSITY("blue_density");
+const std::string LLSettingsSky::SETTING_BLUE_HORIZON("blue_horizon");
+const std::string LLSettingsSky::SETTING_CLOUD_COLOR("cloud_color");
+const std::string LLSettingsSky::SETTING_CLOUD_POS_DENSITY1("cloud_pos_density1");
+const std::string LLSettingsSky::SETTING_CLOUD_POS_DENSITY2("cloud_pos_density2");
+const std::string LLSettingsSky::SETTING_CLOUD_SCALE("cloud_scale");
+const std::string LLSettingsSky::SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate");
+const std::string LLSettingsSky::SETTING_CLOUD_SHADOW("cloud_shadow");
+const std::string LLSettingsSky::SETTING_CLOUD_TEXTUREID("cloud_id");
+const std::string LLSettingsSky::SETTING_DENSITY_MULTIPLIER("density_multiplier");
+const std::string LLSettingsSky::SETTING_DISTANCE_MULTIPLIER("distance_multiplier");
+const std::string LLSettingsSky::SETTING_DOME_OFFSET("dome_offset");
+const std::string LLSettingsSky::SETTING_DOME_RADIUS("dome_radius");
+const std::string LLSettingsSky::SETTING_GAMMA("gamma");
+const std::string LLSettingsSky::SETTING_GLOW("glow");
+const std::string LLSettingsSky::SETTING_HAZE_DENSITY("haze_density");
+const std::string LLSettingsSky::SETTING_HAZE_HORIZON("haze_horizon");
+const std::string LLSettingsSky::SETTING_LIGHT_NORMAL("lightnorm");
+const std::string LLSettingsSky::SETTING_MAX_Y("max_y");
+const std::string LLSettingsSky::SETTING_MOON_ROTATION("moon_rotation");
+const std::string LLSettingsSky::SETTING_MOON_TEXTUREID("moon_id");
+const std::string LLSettingsSky::SETTING_STAR_BRIGHTNESS("star_brightness");
+const std::string LLSettingsSky::SETTING_SUNLIGHT_COLOR("sunlight_color");
+const std::string LLSettingsSky::SETTING_SUN_ROTATION("sun_rotation");
+const std::string LLSettingsSky::SETTING_SUN_TEXUTUREID("sun_id");
+
+const std::string LLSettingsSky::SETTING_LEGACY_EAST_ANGLE("east_angle");
+const std::string LLSettingsSky::SETTING_LEGACY_ENABLE_CLOUD_SCROLL("enable_cloud_scroll");
+const std::string LLSettingsSky::SETTING_LEGACY_SUN_ANGLE("sun_angle");
+
+//=========================================================================
+LLSettingsSky::LLSettingsSky(const LLSD &data) :
+ LLSettingsBase(data)
+{
+}
+
+LLSettingsSky::LLSettingsSky():
+ LLSettingsBase()
+{
+}
+
+void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F32 blendf)
+{
+ LLSettingsSky::ptr_t other = boost::static_pointer_cast<LLSettingsSky>(end);
+ LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+ replaceSettings(blenddata);
+}
+
+
+void LLSettingsSky::setMoonRotation(F32 azimuth, F32 altitude)
+{
+ setValue(SETTING_MOON_ROTATION, ::body_position_from_angles(azimuth, altitude));
+}
+
+LLSettingsSky::azimalt_t LLSettingsSky::getMoonRotationAzAl() const
+{
+ azimalt_t res;
+ ::angles_from_rotation(getMoonRotation(), res.first, res.second);
+
+ return res;
+}
+
+void LLSettingsSky::setSunRotation(F32 azimuth, F32 altitude)
+{
+ setValue(SETTING_SUN_ROTATION, ::body_position_from_angles(azimuth, altitude));
+}
+
+LLSettingsSky::azimalt_t LLSettingsSky::getSunRotationAzAl() const
+{
+ azimalt_t res;
+ ::angles_from_rotation(getSunRotation(), res.first, res.second);
+
+ return res;
+}
+
+LLSettingsSky::stringset_t LLSettingsSky::getSlerpKeys() const
+{
+ static stringset_t slepSet;
+
+ if (slepSet.empty())
+ {
+ slepSet.insert(SETTING_SUN_ROTATION);
+ slepSet.insert(SETTING_MOON_ROTATION);
+ }
+
+ return slepSet;
+}
+
+LLSettingsSky::validation_list_t LLSettingsSky::getValidationList() const
+{
+ static validation_list_t validation;
+
+ if (validation.empty())
+ { // Note the use of LLSD(LLSDArray()()()...) This is due to an issue with the
+ // copy constructor for LLSDArray. Directly binding the LLSDArray as
+ // a parameter without first wrapping it in a pure LLSD object will result
+ // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]]
+
+ validation.push_back(Validator(SETTING_AMBIENT, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
+ validation.push_back(Validator(SETTING_BLOOM_TEXTUREID, true, LLSD::TypeUUID));
+ validation.push_back(Validator(SETTING_BLUE_DENSITY, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(2.0f)(2.0f)(2.0f)("*")))));
+ validation.push_back(Validator(SETTING_BLUE_HORIZON, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(2.0f)(2.0f)(2.0f)("*")))));
+ validation.push_back(Validator(SETTING_CLOUD_COLOR, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*")))));
+ validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY1, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(1.68841f)(1.0f)(1.0f)("*")))));
+ validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY2, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(1.68841f)(1.0f)(1.0f)("*")))));
+ validation.push_back(Validator(SETTING_CLOUD_SCALE, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(0.999f)))));
+ validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)),
+ LLSD(LLSDArray(20.0f)(20.0f)))));
+ validation.push_back(Validator(SETTING_CLOUD_SHADOW, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_CLOUD_TEXTUREID, false, LLSD::TypeUUID));
+ validation.push_back(Validator(SETTING_DENSITY_MULTIPLIER, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.0009f)))));
+ validation.push_back(Validator(SETTING_DISTANCE_MULTIPLIER, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(100.0f)))));
+ validation.push_back(Validator(SETTING_DOME_OFFSET, false, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_DOME_RADIUS, false, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f)))));
+ validation.push_back(Validator(SETTING_GAMMA, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10.0f)))));
+ validation.push_back(Validator(SETTING_GLOW, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.2f)("*")(-2.5f)("*")),
+ LLSD(LLSDArray(20.0f)("*")(0.0f)("*")))));
+ validation.push_back(Validator(SETTING_HAZE_DENSITY, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(4.0f)))));
+ validation.push_back(Validator(SETTING_HAZE_HORIZON, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_LIGHT_NORMAL, false, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorNormalized, _1, 3)));
+ validation.push_back(Validator(SETTING_MAX_Y, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(4000.0f)))));
+ validation.push_back(Validator(SETTING_MOON_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
+ validation.push_back(Validator(SETTING_MOON_TEXTUREID, false, LLSD::TypeUUID));
+ validation.push_back(Validator(SETTING_STAR_BRIGHTNESS, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+ validation.push_back(Validator(SETTING_SUNLIGHT_COLOR, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
+ LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
+ validation.push_back(Validator(SETTING_SUN_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
+ validation.push_back(Validator(SETTING_SUN_TEXUTUREID, false, LLSD::TypeUUID));
+ }
+
+ return validation;
+}
+
+
+LLSD LLSettingsSky::defaults()
+{
+ LLSD dfltsetting;
+
+
+ LLQuaternion sunquat;
+ sunquat.setEulerAngles(1.39626, 0.0, 0.0); // 80deg Azumith/0deg East
+ LLQuaternion moonquat = ~sunquat;
+
+ // Magic constants copied form dfltsetting.xml
+ dfltsetting[SETTING_AMBIENT] = LLColor4::white.getValue();
+ dfltsetting[SETTING_BLUE_DENSITY] = LLColor4(0.2447, 0.4487, 0.7599, 0.0).getValue();
+ dfltsetting[SETTING_BLUE_HORIZON] = LLColor4(0.4954, 0.4954, 0.6399, 0.0).getValue();
+ dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099, 0.4099, 0.4099, 0.0).getValue();
+ dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue();
+ dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue();
+ dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199);
+ dfltsetting[SETTING_CLOUD_SCROLL_RATE] = LLSDArray(10.1999)(10.0109);
+ dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699);
+ dfltsetting[SETTING_DENSITY_MULTIPLIER] = LLSD::Real(0.0001);
+ dfltsetting[SETTING_DISTANCE_MULTIPLIER] = LLSD::Real(0.8000);
+ dfltsetting[SETTING_DOME_OFFSET] = LLSD::Real(0.96f);
+ dfltsetting[SETTING_DOME_RADIUS] = LLSD::Real(15000.f);
+ dfltsetting[SETTING_GAMMA] = LLSD::Real(1.0);
+ dfltsetting[SETTING_GLOW] = LLColor4(5.000, 0.0010, -0.4799, 1.0).getValue();
+ dfltsetting[SETTING_HAZE_DENSITY] = LLSD::Real(0.6999);
+ dfltsetting[SETTING_HAZE_HORIZON] = LLSD::Real(0.1899);
+ dfltsetting[SETTING_LIGHT_NORMAL] = LLVector3(0.0000, 0.9126, -0.4086).getValue();
+ dfltsetting[SETTING_MAX_Y] = LLSD::Real(1605);
+ dfltsetting[SETTING_MOON_ROTATION] = moonquat.getValue();
+ dfltsetting[SETTING_STAR_BRIGHTNESS] = LLSD::Real(0.0000);
+ dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342, 0.7815, 0.8999, 0.0).getValue();
+ dfltsetting[SETTING_SUN_ROTATION] = sunquat.getValue();
+
+ dfltsetting[SETTING_BLOOM_TEXTUREID] = LLUUID::null;
+ dfltsetting[SETTING_CLOUD_TEXTUREID] = LLUUID::null;
+ dfltsetting[SETTING_MOON_TEXTUREID] = IMG_MOON; // gMoonTextureID; // These two are returned by the login... wow!
+ dfltsetting[SETTING_SUN_TEXUTUREID] = IMG_SUN; // gSunTextureID;
+
+ return dfltsetting;
+}
+
+LLSD LLSettingsSky::translateLegacySettings(LLSD legacy)
+{
+ LLSD newsettings(defaults());
+
+ if (legacy.has(SETTING_AMBIENT))
+ {
+ newsettings[SETTING_AMBIENT] = LLColor3(legacy[SETTING_AMBIENT]).getValue();
+ }
+ if (legacy.has(SETTING_BLUE_DENSITY))
+ {
+ newsettings[SETTING_BLUE_DENSITY] = LLColor3(legacy[SETTING_BLUE_DENSITY]).getValue();
+ }
+ if (legacy.has(SETTING_BLUE_HORIZON))
+ {
+ newsettings[SETTING_BLUE_HORIZON] = LLColor3(legacy[SETTING_BLUE_HORIZON]).getValue();
+ }
+ if (legacy.has(SETTING_CLOUD_COLOR))
+ {
+ newsettings[SETTING_CLOUD_COLOR] = LLColor3(legacy[SETTING_CLOUD_COLOR]).getValue();
+ }
+ if (legacy.has(SETTING_CLOUD_POS_DENSITY1))
+ {
+ newsettings[SETTING_CLOUD_POS_DENSITY1] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY1]).getValue();
+ }
+ if (legacy.has(SETTING_CLOUD_POS_DENSITY2))
+ {
+ newsettings[SETTING_CLOUD_POS_DENSITY2] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY2]).getValue();
+ }
+ if (legacy.has(SETTING_CLOUD_SCALE))
+ {
+ newsettings[SETTING_CLOUD_SCALE] = LLSD::Real(legacy[SETTING_CLOUD_SCALE][0].asReal());
+ }
+ if (legacy.has(SETTING_CLOUD_SCROLL_RATE))
+ {
+ LLVector2 cloud_scroll(legacy[SETTING_CLOUD_SCROLL_RATE]);
+
+ if (legacy.has(SETTING_LEGACY_ENABLE_CLOUD_SCROLL))
+ {
+ LLSD enabled = legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL];
+ if (!enabled[0].asBoolean())
+ cloud_scroll.mV[0] = 0.0f;
+ if (!enabled[1].asBoolean())
+ cloud_scroll.mV[1] = 0.0f;
+ }
+
+ newsettings[SETTING_CLOUD_SCROLL_RATE] = cloud_scroll.getValue();
+ }
+ if (legacy.has(SETTING_CLOUD_SHADOW))
+ {
+ newsettings[SETTING_CLOUD_SHADOW] = LLSD::Real(legacy[SETTING_CLOUD_SHADOW][0].asReal());
+ }
+ if (legacy.has(SETTING_DENSITY_MULTIPLIER))
+ {
+ newsettings[SETTING_DENSITY_MULTIPLIER] = LLSD::Real(legacy[SETTING_DENSITY_MULTIPLIER][0].asReal());
+ }
+ if (legacy.has(SETTING_DISTANCE_MULTIPLIER))
+ {
+ newsettings[SETTING_DISTANCE_MULTIPLIER] = LLSD::Real(legacy[SETTING_DISTANCE_MULTIPLIER][0].asReal());
+ }
+ if (legacy.has(SETTING_GAMMA))
+ {
+ newsettings[SETTING_GAMMA] = legacy[SETTING_GAMMA][0].asReal();
+ }
+ if (legacy.has(SETTING_GLOW))
+ {
+ newsettings[SETTING_GLOW] = LLColor3(legacy[SETTING_GLOW]).getValue();
+ }
+ if (legacy.has(SETTING_HAZE_DENSITY))
+ {
+ newsettings[SETTING_HAZE_DENSITY] = LLSD::Real(legacy[SETTING_HAZE_DENSITY][0].asReal());
+ }
+ if (legacy.has(SETTING_HAZE_HORIZON))
+ {
+ newsettings[SETTING_HAZE_HORIZON] = LLSD::Real(legacy[SETTING_HAZE_HORIZON][0].asReal());
+ }
+ if (legacy.has(SETTING_LIGHT_NORMAL))
+ {
+ newsettings[SETTING_LIGHT_NORMAL] = LLVector3(legacy[SETTING_LIGHT_NORMAL]).getValue();
+ }
+ if (legacy.has(SETTING_MAX_Y))
+ {
+ newsettings[SETTING_MAX_Y] = LLSD::Real(legacy[SETTING_MAX_Y][0].asReal());
+ }
+ if (legacy.has(SETTING_STAR_BRIGHTNESS))
+ {
+ newsettings[SETTING_STAR_BRIGHTNESS] = LLSD::Real(legacy[SETTING_STAR_BRIGHTNESS].asReal());
+ }
+ if (legacy.has(SETTING_SUNLIGHT_COLOR))
+ {
+ newsettings[SETTING_SUNLIGHT_COLOR] = LLColor4(legacy[SETTING_SUNLIGHT_COLOR]).getValue();
+ }
+
+ if (legacy.has(SETTING_LEGACY_EAST_ANGLE) && legacy.has(SETTING_LEGACY_SUN_ANGLE))
+ { // convert the east and sun angles into a quaternion.
+ F32 azimuth = legacy[SETTING_LEGACY_EAST_ANGLE].asReal();
+ F32 altitude = legacy[SETTING_LEGACY_SUN_ANGLE].asReal();
+
+ LLQuaternion sunquat = ::body_position_from_angles(azimuth, altitude);
+ LLQuaternion moonquat = ::body_position_from_angles(azimuth + F_PI, -altitude);
+
+ F32 az(0), al(0);
+ ::angles_from_rotation(sunquat, az, al);
+
+ newsettings[SETTING_SUN_ROTATION] = sunquat.getValue();
+ newsettings[SETTING_MOON_ROTATION] = moonquat.getValue();
+ }
+
+ return newsettings;
+}
+
+void LLSettingsSky::updateSettings()
+{
+ LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKYVALUES);
+ //LL_INFOS("WINDLIGHT", "SKY", "EEP") << "WL Parameters are dirty. Reticulating Splines..." << LL_ENDL;
+
+ // base class clears dirty flag so as to not trigger recursive update
+ LLSettingsBase::updateSettings();
+
+ calculateHeavnlyBodyPositions();
+ calculateLightSettings();
+}
+
+void LLSettingsSky::calculateHeavnlyBodyPositions()
+{
+ mSunDirection = DUE_EAST * getSunRotation();
+ mSunDirection.normalize();
+ mMoonDirection = DUE_EAST * getMoonRotation();
+ mMoonDirection.normalize();
+
+ // is the normal from the sun or the moon
+ if (mSunDirection.mV[1] >= 0.0)
+ {
+ mLightDirection = mSunDirection;
+ }
+ else if (mSunDirection.mV[1] < 0.0 && mSunDirection.mV[1] > NIGHTTIME_ELEVATION_COS)
+ {
+ // clamp v1 to 0 so sun never points up and causes weirdness on some machines
+ LLVector3 vec(mSunDirection);
+ vec.mV[1] = 0.0;
+ vec.normalize();
+ mLightDirection = vec;
+ }
+ else
+ {
+ mLightDirection = mMoonDirection;
+ }
+
+ // calculate the clamp lightnorm for sky (to prevent ugly banding in sky
+ // when haze goes below the horizon
+ mClampedLightDirection = mLightDirection;
+
+ if (mClampedLightDirection.mV[1] < -0.1f)
+ {
+ mClampedLightDirection.mV[1] = -0.1f;
+ mClampedLightDirection.normalize();
+ }
+}
+
+void LLSettingsSky::calculateLightSettings()
+{
+ LLColor3 vary_HazeColor;
+ LLColor3 vary_SunlightColor;
+ LLColor3 vary_AmbientColor;
+ {
+ // Initialize temp variables
+ LLColor3 sunlight = getSunlightColor();
+ LLColor3 ambient = getAmbientColor();
+ F32 gamma = getGamma();
+ LLColor3 blue_density = getBlueDensity();
+ LLColor3 blue_horizon = getBlueHorizon();
+ F32 haze_density = getHazeDensity();
+ F32 haze_horizon = getHazeHorizon();
+ F32 density_multiplier = getDensityMultiplier();
+ F32 max_y = getMaxY();
+ F32 cloud_shadow = getCloudShadow();
+ LLVector3 lightnorm = getLightDirection();
+
+ // Sunlight attenuation effect (hue and brightness) due to atmosphere
+ // this is used later for sunlight modulation at various altitudes
+ LLColor3 light_atten =
+ (blue_density * 1.0 + smear(haze_density * 0.25f)) * (density_multiplier * max_y);
+
+ // Calculate relative weights
+ LLColor3 temp2(0.f, 0.f, 0.f);
+ LLColor3 temp1 = blue_density + smear(haze_density);
+ LLColor3 blue_weight = componentDiv(blue_density, temp1);
+ LLColor3 haze_weight = componentDiv(smear(haze_density), temp1);
+
+ // Compute sunlight from P & lightnorm (for long rays like sky)
+ /// USE only lightnorm.
+ // temp2[1] = llmax(0.f, llmax(0.f, Pn[1]) * 1.0f + lightnorm[1] );
+
+ // and vary_sunlight will work properly with moon light
+ F32 lighty = lightnorm[1];
+ if (lighty < NIGHTTIME_ELEVATION_COS)
+ {
+ lighty = -lighty;
+ }
+
+ temp2.mV[1] = llmax(0.f, lighty);
+ if(temp2.mV[1] > 0.f)
+ {
+ temp2.mV[1] = 1.f / temp2.mV[1];
+ }
+ componentMultBy(sunlight, componentExp((light_atten * -1.f) * temp2.mV[1]));
+
+ // Distance
+ temp2.mV[2] = density_multiplier;
+
+ // Transparency (-> temp1)
+ temp1 = componentExp((temp1 * -1.f) * temp2.mV[2]);
+
+ // vary_AtmosAttenuation = temp1;
+
+ //increase ambient when there are more clouds
+ LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5f;
+
+ //haze color
+ vary_HazeColor =
+ (blue_horizon * blue_weight * (sunlight*(1.f - cloud_shadow) + tmpAmbient)
+ + componentMult(haze_horizon * haze_weight, sunlight*(1.f - cloud_shadow) * temp2.mV[0] + tmpAmbient)
+ );
+
+ //brightness of surface both sunlight and ambient
+ vary_SunlightColor = componentMult(sunlight, temp1) * 1.f;
+ vary_SunlightColor.clamp();
+ vary_SunlightColor = smear(1.0f) - vary_SunlightColor;
+ vary_SunlightColor = componentPow(vary_SunlightColor, gamma);
+ vary_SunlightColor = smear(1.0f) - vary_SunlightColor;
+ vary_AmbientColor = componentMult(tmpAmbient, temp1) * 0.5;
+ vary_AmbientColor.clamp();
+ vary_AmbientColor = smear(1.0f) - vary_AmbientColor;
+ vary_AmbientColor = componentPow(vary_AmbientColor, gamma);
+ vary_AmbientColor = smear(1.0f) - vary_AmbientColor;
+
+ componentMultBy(vary_HazeColor, LLColor3(1.f, 1.f, 1.f) - temp1);
+
+ }
+
+ mSunDiffuse = vary_SunlightColor;
+ mSunAmbient = vary_AmbientColor;
+ mMoonDiffuse = vary_SunlightColor;
+ mMoonAmbient = vary_AmbientColor;
+
+ mTotalAmbient = LLColor4(vary_AmbientColor, 1.0f);
+
+ mFadeColor = mTotalAmbient + (mSunDiffuse + mMoonDiffuse) * 0.5f;
+ mFadeColor.setAlpha(0);
+}
+
+
+//=========================================================================
+namespace
+{
+ LLQuaternion body_position_from_angles(F32 azimuth, F32 altitude)
+ {
+ // Azimuth is traditionally calculated from North, we are going from East.
+ LLQuaternion rot_azi;
+ LLQuaternion rot_alt;
+
+ rot_azi.setAngleAxis(azimuth, VECT_ZENITH);
+ rot_alt.setAngleAxis(-altitude, VECT_NORTHSOUTH);
+
+ LLQuaternion body_quat = rot_alt * rot_azi;
+ body_quat.normalize();
+
+ //LLVector3 sun_vector = (DUE_EAST * body_quat);
+ //_WARNS("RIDER") << "Azimuth=" << azimuth << " Altitude=" << altitude << " Body Vector=" << sun_vector.getValue() << LL_ENDL;
+ return body_quat;
+ }
+
+ void angles_from_rotation(LLQuaternion quat, F32 &azimuth, F32 &altitude)
+ {
+ LLVector3 body_vector = (DUE_EAST * quat);
+
+ LLVector3 body_az(body_vector[0], 0.f, body_vector[2]);
+ LLVector3 body_al(0.f, body_vector[1], body_vector[2]);
+
+ if (fabs(body_az.normalize()) > 0.001)
+ azimuth = angle_between(DUE_EAST, body_az);
+ else
+ azimuth = 0.0f;
+
+ if (fabs(body_al.normalize()) > 0.001)
+ altitude = angle_between(DUE_EAST, body_al);
+ else
+ altitude = 0.0f;
+ }
+}
+
+
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
new file mode 100644
index 0000000000..ff4b62f86e
--- /dev/null
+++ b/indra/llinventory/llsettingssky.h
@@ -0,0 +1,455 @@
+/**
+* @file llsettingssky.h
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SETTINGS_SKY_H
+#define LL_SETTINGS_SKY_H
+
+#include "llsettingsbase.h"
+#include "v4coloru.h"
+
+class LLSettingsSky: public LLSettingsBase
+{
+public:
+ static const std::string SETTING_AMBIENT;
+ static const std::string SETTING_BLOOM_TEXTUREID;
+ static const std::string SETTING_BLUE_DENSITY;
+ static const std::string SETTING_BLUE_HORIZON;
+ static const std::string SETTING_CLOUD_COLOR;
+ static const std::string SETTING_CLOUD_POS_DENSITY1;
+ static const std::string SETTING_CLOUD_POS_DENSITY2;
+ static const std::string SETTING_CLOUD_SCALE;
+ static const std::string SETTING_CLOUD_SCROLL_RATE;
+ static const std::string SETTING_CLOUD_SHADOW;
+ static const std::string SETTING_CLOUD_TEXTUREID;
+ static const std::string SETTING_DENSITY_MULTIPLIER;
+ static const std::string SETTING_DISTANCE_MULTIPLIER;
+ static const std::string SETTING_DOME_OFFSET;
+ static const std::string SETTING_DOME_RADIUS;
+ static const std::string SETTING_GAMMA;
+ static const std::string SETTING_GLOW;
+ static const std::string SETTING_HAZE_DENSITY;
+ static const std::string SETTING_HAZE_HORIZON;
+ static const std::string SETTING_LIGHT_NORMAL;
+ static const std::string SETTING_MAX_Y;
+ static const std::string SETTING_MOON_ROTATION;
+ static const std::string SETTING_MOON_TEXTUREID;
+ static const std::string SETTING_STAR_BRIGHTNESS;
+ static const std::string SETTING_SUNLIGHT_COLOR;
+ static const std::string SETTING_SUN_ROTATION;
+ static const std::string SETTING_SUN_TEXUTUREID;
+
+ typedef boost::shared_ptr<LLSettingsSky> ptr_t;
+ typedef std::pair<F32, F32> azimalt_t;
+
+ //---------------------------------------------------------------------
+ LLSettingsSky(const LLSD &data);
+ virtual ~LLSettingsSky() { };
+
+ virtual ptr_t buildClone() = 0;
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const { return std::string("sky"); }
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &end, F32 blendf);
+
+ static LLSD defaults();
+
+ //---------------------------------------------------------------------
+ LLColor3 getAmbientColor() const
+ {
+ return LLColor3(mSettings[SETTING_AMBIENT]);
+ }
+
+ void setAmbientColor(const LLColor3 &val)
+ {
+ setValue(SETTING_AMBIENT, val);
+ }
+
+ LLUUID getBloomTextureId() const
+ {
+ return mSettings[SETTING_BLOOM_TEXTUREID].asUUID();
+ }
+
+ LLColor3 getBlueDensity() const
+ {
+ return LLColor3(mSettings[SETTING_BLUE_DENSITY]);
+ }
+
+ void setBlueDensity(const LLColor3 &val)
+ {
+ setValue(SETTING_BLUE_DENSITY, val);
+ }
+
+ LLColor3 getBlueHorizon() const
+ {
+ return LLColor3(mSettings[SETTING_BLUE_HORIZON]);
+ }
+
+ void setBlueHorizon(const LLColor3 &val)
+ {
+ setValue(SETTING_BLUE_HORIZON, val);
+ }
+
+ LLColor3 getCloudColor() const
+ {
+ return LLColor3(mSettings[SETTING_CLOUD_COLOR]);
+ }
+
+ void setCloudColor(const LLColor3 &val)
+ {
+ setValue(SETTING_CLOUD_COLOR, val);
+ }
+
+ LLUUID getCloudNoiseTextureId() const
+ {
+ return mSettings[SETTING_CLOUD_TEXTUREID].asUUID();
+ }
+
+ LLColor3 getCloudPosDensity1() const
+ {
+ return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY1]);
+ }
+
+ void setCloudPosDensity1(const LLColor3 &val)
+ {
+ setValue(SETTING_CLOUD_POS_DENSITY1, val);
+ }
+
+ LLColor3 getCloudPosDensity2() const
+ {
+ return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY2]);
+ }
+
+ void setCloudPosDensity2(const LLColor3 &val)
+ {
+ setValue(SETTING_CLOUD_POS_DENSITY2, val);
+ }
+
+ F32 getCloudScale() const
+ {
+ return mSettings[SETTING_CLOUD_SCALE].asReal();
+ }
+
+ void setCloudScale(F32 val)
+ {
+ setValue(SETTING_CLOUD_SCALE, val);
+ }
+
+ LLVector2 getCloudScrollRate() const
+ {
+ return LLVector2(mSettings[SETTING_CLOUD_SCROLL_RATE]);
+ }
+
+ void setCloudScrollRate(const LLVector2 &val)
+ {
+ setValue(SETTING_CLOUD_SCROLL_RATE, val);
+ }
+
+ void setCloudScrollRateX(F32 val)
+ {
+ mSettings[SETTING_CLOUD_SCROLL_RATE][0] = val;
+ setDirtyFlag(true);
+ }
+
+ void setCloudScrollRateY(F32 val)
+ {
+ mSettings[SETTING_CLOUD_SCROLL_RATE][1] = val;
+ setDirtyFlag(true);
+ }
+
+ F32 getCloudShadow() const
+ {
+ return mSettings[SETTING_CLOUD_SHADOW].asReal();
+ }
+
+ void setCloudShadow(F32 val)
+ {
+ setValue(SETTING_CLOUD_SHADOW, val);
+ }
+
+ F32 getDensityMultiplier() const
+ {
+ return mSettings[SETTING_DENSITY_MULTIPLIER].asReal();
+ }
+
+ void setDensityMultiplier(F32 val)
+ {
+ setValue(SETTING_DENSITY_MULTIPLIER, val);
+ }
+
+ F32 getDistanceMultiplier() const
+ {
+ return mSettings[SETTING_DISTANCE_MULTIPLIER].asReal();
+ }
+
+ void setDistanceMultiplier(F32 val)
+ {
+ setValue(SETTING_DISTANCE_MULTIPLIER, val);
+ }
+
+ F32 getDomeOffset() const
+ {
+ return DOME_OFFSET;
+ //return mSettings[SETTING_DOME_OFFSET].asReal();
+ }
+
+ F32 getDomeRadius() const
+ {
+ return DOME_RADIUS;
+ //return mSettings[SETTING_DOME_RADIUS].asReal();
+ }
+
+ F32 getGamma() const
+ {
+ return mSettings[SETTING_GAMMA].asReal();
+ }
+
+ void setGamma(F32 val)
+ {
+ mSettings[SETTING_GAMMA] = LLSD::Real(val);
+ setDirtyFlag(true);
+ }
+
+ LLColor3 getGlow() const
+ {
+ return LLColor3(mSettings[SETTING_GLOW]);
+ }
+
+ void setGlow(const LLColor3 &val)
+ {
+ setValue(SETTING_GLOW, val);
+ }
+
+ F32 getHazeDensity() const
+ {
+ return mSettings[SETTING_HAZE_DENSITY].asReal();
+ }
+
+ void setHazeDensity(F32 val)
+ {
+ setValue(SETTING_HAZE_DENSITY, val);
+ }
+
+ F32 getHazeHorizon() const
+ {
+ return mSettings[SETTING_HAZE_HORIZON].asReal();
+ }
+
+ void setHazeHorizon(F32 val)
+ {
+ setValue(SETTING_HAZE_HORIZON, val);
+ }
+
+ LLVector3 getLightNormal() const
+ {
+ return LLVector3(mSettings[SETTING_LIGHT_NORMAL]);
+ }
+
+ void setLightNormal(const LLVector3 &val)
+ {
+ setValue(SETTING_LIGHT_NORMAL, val);
+ }
+
+ F32 getMaxY() const
+ {
+ return mSettings[SETTING_MAX_Y].asReal();
+ }
+
+ LLQuaternion getMoonRotation() const
+ {
+ return LLQuaternion(mSettings[SETTING_MOON_ROTATION]);
+ }
+
+ void setMoonRotation(const LLQuaternion &val)
+ {
+ setValue(SETTING_MOON_ROTATION, val);
+ }
+
+ azimalt_t getMoonRotationAzAl() const;
+
+ void setMoonRotation(F32 azimuth, F32 altitude);
+
+ void setMoonRotation(const azimalt_t &azialt)
+ {
+ setMoonRotation(azialt.first, azialt.second);
+ }
+
+ LLUUID getMoonTextureId() const
+ {
+ return mSettings[SETTING_MOON_TEXTUREID].asUUID();
+ }
+
+ F32 getStarBrightness() const
+ {
+ return mSettings[SETTING_STAR_BRIGHTNESS].asReal();
+ }
+
+ void setStarBrightness(F32 val)
+ {
+ setValue(SETTING_STAR_BRIGHTNESS, val);
+ }
+
+ LLColor3 getSunlightColor() const
+ {
+ return LLColor3(mSettings[SETTING_SUNLIGHT_COLOR]);
+ }
+
+ void setSunlightColor(const LLColor3 &val)
+ {
+ setValue(SETTING_SUNLIGHT_COLOR, val);
+ }
+
+ LLQuaternion getSunRotation() const
+ {
+ return LLQuaternion(mSettings[SETTING_SUN_ROTATION]);
+ }
+
+ azimalt_t getSunRotationAzAl() const;
+
+ void setSunRotation(const LLQuaternion &val)
+ {
+ setValue(SETTING_SUN_ROTATION, val);
+ }
+
+ void setSunRotation(F32 azimuth, F32 altitude);
+
+ void setSunRotation(const azimalt_t & azimalt)
+ {
+ setSunRotation(azimalt.first, azimalt.second);
+ }
+
+ LLUUID getSunTextureId() const
+ {
+ return mSettings[SETTING_SUN_TEXUTUREID].asUUID();
+ }
+
+ // Internal/calculated settings
+ LLVector3 getLightDirection() const
+ {
+ update();
+ return mLightDirection;
+ };
+
+ LLVector3 getClampedLightDirection() const
+ {
+ update();
+ return mClampedLightDirection;
+ };
+
+ LLVector3 getSunDirection() const
+ {
+ update();
+ return mSunDirection;
+ }
+
+ LLVector3 getMoonDirection() const
+ {
+ update();
+ return mMoonDirection;
+ }
+
+ LLColor4U getFadeColor() const
+ {
+ update();
+ return mFadeColor;
+ }
+
+ LLColor4 getMoonAmbient() const
+ {
+ update();
+ return mMoonAmbient;
+ }
+
+ LLColor3 getMoonDiffuse() const
+ {
+ update();
+ return mMoonDiffuse;
+ }
+
+ LLColor4 getSunAmbient() const
+ {
+ update();
+ return mSunAmbient;
+ }
+
+ LLColor3 getSunDiffuse() const
+ {
+ update();
+ return mSunDiffuse;
+ }
+
+ LLColor4 getTotalAmbient() const
+ {
+ update();
+ return mTotalAmbient;
+ }
+
+protected:
+ LLSettingsSky();
+
+ virtual stringset_t getSlerpKeys() const;
+
+ virtual validation_list_t getValidationList() const;
+
+ virtual void updateSettings();
+
+ static LLSD translateLegacySettings(LLSD legacy);
+
+private:
+ static const std::string SETTING_LEGACY_EAST_ANGLE;
+ static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL;
+ static const std::string SETTING_LEGACY_SUN_ANGLE;
+
+ static const F32 NIGHTTIME_ELEVATION;
+ static const F32 NIGHTTIME_ELEVATION_COS;
+
+ void calculateHeavnlyBodyPositions();
+ void calculateLightSettings();
+
+ LLVector3 mSunDirection;
+ LLVector3 mMoonDirection;
+ LLVector3 mLightDirection;
+ LLVector3 mClampedLightDirection;
+
+ static const F32 DOME_RADIUS;
+ static const F32 DOME_OFFSET;
+
+ LLColor4U mFadeColor;
+ LLColor4 mMoonAmbient;
+ LLColor3 mMoonDiffuse;
+ LLColor4 mSunAmbient;
+ LLColor3 mSunDiffuse;
+
+ LLColor4 mTotalAmbient;
+
+ typedef std::map<std::string, S32> mapNameToUniformId_t;
+
+ static mapNameToUniformId_t sNameToUniformMapping;
+};
+
+#endif
diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp
new file mode 100644
index 0000000000..1b960746d5
--- /dev/null
+++ b/indra/llinventory/llsettingswater.cpp
@@ -0,0 +1,215 @@
+/**
+* @file llsettingswater.h
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "llsettingswater.h"
+#include <algorithm>
+#include <boost/make_shared.hpp>
+#include "lltrace.h"
+#include "llfasttimer.h"
+#include "v3colorutil.h"
+#include "indra_constants.h"
+
+//=========================================================================
+namespace
+{
+ LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment");
+ LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment");
+}
+
+//=========================================================================
+const std::string LLSettingsWater::SETTING_BLUR_MULTIPILER("blur_multiplier");
+const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color");
+const std::string LLSettingsWater::SETTING_FOG_DENSITY("water_fog_density");
+const std::string LLSettingsWater::SETTING_FOG_MOD("underwater_fog_mod");
+const std::string LLSettingsWater::SETTING_FRESNEL_OFFSET("fresnel_offset");
+const std::string LLSettingsWater::SETTING_FRESNEL_SCALE("fresnel_scale");
+const std::string LLSettingsWater::SETTING_NORMAL_MAP("normal_map");
+const std::string LLSettingsWater::SETTING_NORMAL_SCALE("normal_scale");
+const std::string LLSettingsWater::SETTING_SCALE_ABOVE("scale_above");
+const std::string LLSettingsWater::SETTING_SCALE_BELOW("scale_below");
+const std::string LLSettingsWater::SETTING_WAVE1_DIR("wave1_direction");
+const std::string LLSettingsWater::SETTING_WAVE2_DIR("wave2_direction");
+
+const std::string LLSettingsWater::SETTING_LEGACY_BLUR_MULTIPILER("blurMultiplier");
+const std::string LLSettingsWater::SETTING_LEGACY_FOG_COLOR("waterFogColor");
+const std::string LLSettingsWater::SETTING_LEGACY_FOG_DENSITY("waterFogDensity");
+const std::string LLSettingsWater::SETTING_LEGACY_FOG_MOD("underWaterFogMod");
+const std::string LLSettingsWater::SETTING_LEGACY_FRESNEL_OFFSET("fresnelOffset");
+const std::string LLSettingsWater::SETTING_LEGACY_FRESNEL_SCALE("fresnelScale");
+const std::string LLSettingsWater::SETTING_LEGACY_NORMAL_MAP("normalMap");
+const std::string LLSettingsWater::SETTING_LEGACY_NORMAL_SCALE("normScale");
+const std::string LLSettingsWater::SETTING_LEGACY_SCALE_ABOVE("scaleAbove");
+const std::string LLSettingsWater::SETTING_LEGACY_SCALE_BELOW("scaleBelow");
+const std::string LLSettingsWater::SETTING_LEGACY_WAVE1_DIR("wave1Dir");
+const std::string LLSettingsWater::SETTING_LEGACY_WAVE2_DIR("wave2Dir");
+
+const LLUUID LLSettingsWater::DEFAULT_WATER_NORMAL_ID(DEFAULT_WATER_NORMAL);
+
+
+//=========================================================================
+LLSettingsWater::LLSettingsWater(const LLSD &data) :
+ LLSettingsBase(data)
+{
+}
+
+LLSettingsWater::LLSettingsWater() :
+ LLSettingsBase()
+{
+}
+
+//=========================================================================
+LLSD LLSettingsWater::defaults()
+{
+ LLSD dfltsetting;
+
+ // Magic constants copied form defaults.xml
+ dfltsetting[SETTING_BLUR_MULTIPILER] = LLSD::Real(0.04000f);
+ dfltsetting[SETTING_FOG_COLOR] = LLColor3(0.0156f, 0.1490f, 0.2509f).getValue();
+ dfltsetting[SETTING_FOG_DENSITY] = LLSD::Real(2.0f);
+ dfltsetting[SETTING_FOG_MOD] = LLSD::Real(0.25f);
+ dfltsetting[SETTING_FRESNEL_OFFSET] = LLSD::Real(0.5f);
+ dfltsetting[SETTING_FRESNEL_SCALE] = LLSD::Real(0.3999);
+ dfltsetting[SETTING_NORMAL_MAP] = LLSD::UUID(DEFAULT_WATER_NORMAL_ID);
+ dfltsetting[SETTING_NORMAL_SCALE] = LLVector3(2.0f, 2.0f, 2.0f).getValue();
+ dfltsetting[SETTING_SCALE_ABOVE] = LLSD::Real(0.0299f);
+ dfltsetting[SETTING_SCALE_BELOW] = LLSD::Real(0.2000f);
+ dfltsetting[SETTING_WAVE1_DIR] = LLVector2(1.04999f, -0.42000f).getValue();
+ dfltsetting[SETTING_WAVE2_DIR] = LLVector2(1.10999f, -1.16000f).getValue();
+
+ return dfltsetting;
+}
+
+LLSD LLSettingsWater::translateLegacySettings(LLSD legacy)
+{
+ LLSD newsettings(defaults());
+
+ if (legacy.has(SETTING_LEGACY_BLUR_MULTIPILER))
+ {
+ newsettings[SETTING_BLUR_MULTIPILER] = LLSD::Real(legacy[SETTING_LEGACY_BLUR_MULTIPILER].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_FOG_COLOR))
+ {
+ newsettings[SETTING_FOG_COLOR] = LLColor3(legacy[SETTING_LEGACY_FOG_COLOR]).getValue();
+ }
+ if (legacy.has(SETTING_LEGACY_FOG_DENSITY))
+ {
+ newsettings[SETTING_FOG_DENSITY] = LLSD::Real(legacy[SETTING_LEGACY_FOG_DENSITY]);
+ }
+ if (legacy.has(SETTING_LEGACY_FOG_MOD))
+ {
+ newsettings[SETTING_FOG_MOD] = LLSD::Real(legacy[SETTING_LEGACY_FOG_MOD].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_FRESNEL_OFFSET))
+ {
+ newsettings[SETTING_FRESNEL_OFFSET] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_OFFSET].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_FRESNEL_SCALE))
+ {
+ newsettings[SETTING_FRESNEL_SCALE] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_SCALE].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_NORMAL_MAP))
+ {
+ newsettings[SETTING_NORMAL_MAP] = LLSD::UUID(legacy[SETTING_LEGACY_NORMAL_MAP].asUUID());
+ }
+ if (legacy.has(SETTING_LEGACY_NORMAL_SCALE))
+ {
+ newsettings[SETTING_NORMAL_SCALE] = LLVector3(legacy[SETTING_LEGACY_NORMAL_SCALE]).getValue();
+ }
+ if (legacy.has(SETTING_LEGACY_SCALE_ABOVE))
+ {
+ newsettings[SETTING_SCALE_ABOVE] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_ABOVE].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_SCALE_BELOW))
+ {
+ newsettings[SETTING_SCALE_BELOW] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_BELOW].asReal());
+ }
+ if (legacy.has(SETTING_LEGACY_WAVE1_DIR))
+ {
+ newsettings[SETTING_WAVE1_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE1_DIR]).getValue();
+ }
+ if (legacy.has(SETTING_LEGACY_WAVE2_DIR))
+ {
+ newsettings[SETTING_WAVE2_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE2_DIR]).getValue();
+ }
+
+ return newsettings;
+}
+
+void LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F32 blendf)
+{
+ LLSettingsWater::ptr_t other = boost::static_pointer_cast<LLSettingsWater>(end);
+ LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+ replaceSettings(blenddata);
+}
+
+LLSettingsWater::validation_list_t LLSettingsWater::getValidationList() const
+{
+ static validation_list_t validation;
+
+ if (validation.empty())
+ { // Note the use of LLSD(LLSDArray()()()...) This is due to an issue with the
+ // copy constructor for LLSDArray. Directly binding the LLSDArray as
+ // a parameter without first wrapping it in a pure LLSD object will result
+ // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]]
+
+ validation.push_back(Validator(SETTING_BLUR_MULTIPILER, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.16f)))));
+ validation.push_back(Validator(SETTING_FOG_COLOR, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)(1.0f)),
+ LLSD(LLSDArray(1.0f)(1.0f)(1.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1.0f)(1024.0f)))));
+ validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1.0f)(1024.0f)))));
+ validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_FRESNEL_SCALE, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_NORMAL_MAP, true, LLSD::TypeUUID));
+ validation.push_back(Validator(SETTING_NORMAL_SCALE, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(0.0f)(0.0f)(0.0f)),
+ LLSD(LLSDArray(10.0f)(10.0f)(10.0f)))));
+ validation.push_back(Validator(SETTING_SCALE_ABOVE, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_SCALE_BELOW, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ validation.push_back(Validator(SETTING_WAVE1_DIR, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(-4.0f)(-4.0f)),
+ LLSD(LLSDArray(4.0f)(4.0f)))));
+ validation.push_back(Validator(SETTING_WAVE2_DIR, true, LLSD::TypeArray,
+ boost::bind(&Validator::verifyVectorMinMax, _1,
+ LLSD(LLSDArray(-4.0f)(-4.0f)),
+ LLSD(LLSDArray(4.0f)(4.0f)))));
+ }
+
+ return validation;
+}
+
diff --git a/indra/llinventory/llsettingswater.h b/indra/llinventory/llsettingswater.h
new file mode 100644
index 0000000000..5d6a482d56
--- /dev/null
+++ b/indra/llinventory/llsettingswater.h
@@ -0,0 +1,227 @@
+/**
+* @file llsettingssky.h
+* @author optional
+* @brief A base class for asset based settings groups.
+*
+* $LicenseInfo:2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2017, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#ifndef LL_SETTINGS_WATER_H
+#define LL_SETTINGS_WATER_H
+
+#include "llsettingsbase.h"
+
+class LLSettingsWater : public LLSettingsBase
+{
+public:
+ static const std::string SETTING_BLUR_MULTIPILER;
+ static const std::string SETTING_FOG_COLOR;
+ static const std::string SETTING_FOG_DENSITY;
+ static const std::string SETTING_FOG_MOD;
+ static const std::string SETTING_FRESNEL_OFFSET;
+ static const std::string SETTING_FRESNEL_SCALE;
+ static const std::string SETTING_NORMAL_MAP;
+ static const std::string SETTING_NORMAL_SCALE;
+ static const std::string SETTING_SCALE_ABOVE;
+ static const std::string SETTING_SCALE_BELOW;
+ static const std::string SETTING_WAVE1_DIR;
+ static const std::string SETTING_WAVE2_DIR;
+
+ static const LLUUID DEFAULT_WATER_NORMAL_ID;
+
+ typedef boost::shared_ptr<LLSettingsWater> ptr_t;
+
+ //---------------------------------------------------------------------
+ LLSettingsWater(const LLSD &data);
+ virtual ~LLSettingsWater() { };
+
+ virtual ptr_t buildClone() = 0;
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const { return std::string("water"); }
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &end, F32 blendf);
+
+ static LLSD defaults();
+
+ //---------------------------------------------------------------------
+ F32 getBlurMultiplier() const
+ {
+ return mSettings[SETTING_BLUR_MULTIPILER].asReal();
+ }
+
+ void setBlurMultiplier(F32 val)
+ {
+ setValue(SETTING_BLUR_MULTIPILER, val);
+ }
+
+ LLColor3 getFogColor() const
+ {
+ return LLColor3(mSettings[SETTING_FOG_COLOR]);
+ }
+
+ void setFogColor(LLColor3 val)
+ {
+ setValue(SETTING_FOG_COLOR, val);
+ }
+
+ F32 getFogDensity() const
+ {
+ return mSettings[SETTING_FOG_DENSITY].asReal();
+ }
+
+ void setFogDensity(F32 val)
+ {
+ setValue(SETTING_FOG_DENSITY, val);
+ }
+
+ F32 getFogMod() const
+ {
+ return mSettings[SETTING_FOG_MOD].asReal();
+ }
+
+ void setFogMod(F32 val)
+ {
+ setValue(SETTING_FOG_MOD, val);
+ }
+
+ F32 getFresnelOffset() const
+ {
+ return mSettings[SETTING_FRESNEL_OFFSET].asReal();
+ }
+
+ void setFresnelOffset(F32 val)
+ {
+ setValue(SETTING_FRESNEL_OFFSET, val);
+ }
+
+ F32 getFresnelScale() const
+ {
+ return mSettings[SETTING_FRESNEL_SCALE].asReal();
+ }
+
+ void setFresnelScale(F32 val)
+ {
+ setValue(SETTING_FRESNEL_SCALE, val);
+ }
+
+ LLUUID getNormalMapID() const
+ {
+ return mSettings[SETTING_NORMAL_MAP].asUUID();
+ }
+
+ void setNormalMapID(LLUUID val)
+ {
+ setValue(SETTING_NORMAL_MAP, val);
+ }
+
+ LLVector3 getNormalScale() const
+ {
+ return LLVector3(mSettings[SETTING_NORMAL_SCALE]);
+ }
+
+ void setNormalScale(LLVector3 val)
+ {
+ setValue(SETTING_NORMAL_SCALE, val);
+ }
+
+ F32 getScaleAbove() const
+ {
+ return mSettings[SETTING_SCALE_ABOVE].asReal();
+ }
+
+ void setScaleAbove(F32 val)
+ {
+ setValue(SETTING_SCALE_ABOVE, val);
+ }
+
+ F32 getScaleBelow() const
+ {
+ return mSettings[SETTING_SCALE_BELOW].asReal();
+ }
+
+ void setScaleBelow(F32 val)
+ {
+ setValue(SETTING_SCALE_BELOW, val);
+ }
+
+ LLVector2 getWave1Dir() const
+ {
+ return LLVector2(mSettings[SETTING_WAVE1_DIR]);
+ }
+
+ void setWave1Dir(LLVector2 val)
+ {
+ setValue(SETTING_WAVE1_DIR, val);
+ }
+
+ LLVector2 getWave2Dir() const
+ {
+ return LLVector2(mSettings[SETTING_WAVE2_DIR]);
+ }
+
+ void setWave2Dir(LLVector2 val)
+ {
+ setValue(SETTING_WAVE2_DIR, val);
+ }
+
+ //-------------------------------------------
+ LLVector4 getWaterPlane() const
+ {
+ update();
+ return mWaterPlane;
+ }
+
+ F32 getWaterFogKS() const
+ {
+ update();
+ return mWaterFogKS;
+ }
+
+protected:
+ LLSettingsWater();
+
+ virtual validation_list_t getValidationList() const;
+
+ static LLSD translateLegacySettings(LLSD legacy);
+
+ LLVector4 mWaterPlane;
+ F32 mWaterFogKS;
+
+private:
+ static const std::string SETTING_LEGACY_BLUR_MULTIPILER;
+ static const std::string SETTING_LEGACY_FOG_COLOR;
+ static const std::string SETTING_LEGACY_FOG_DENSITY;
+ static const std::string SETTING_LEGACY_FOG_MOD;
+ static const std::string SETTING_LEGACY_FRESNEL_OFFSET;
+ static const std::string SETTING_LEGACY_FRESNEL_SCALE;
+ static const std::string SETTING_LEGACY_NORMAL_MAP;
+ static const std::string SETTING_LEGACY_NORMAL_SCALE;
+ static const std::string SETTING_LEGACY_SCALE_ABOVE;
+ static const std::string SETTING_LEGACY_SCALE_BELOW;
+ static const std::string SETTING_LEGACY_WAVE1_DIR;
+ static const std::string SETTING_LEGACY_WAVE2_DIR;
+
+};
+
+#endif