summaryrefslogtreecommitdiff
path: root/indra/llinventory
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llinventory')
-rw-r--r--indra/llinventory/CMakeLists.txt11
-rw-r--r--indra/llinventory/llfoldertype.cpp2
-rw-r--r--indra/llinventory/llinventorydefines.h7
-rw-r--r--indra/llinventory/llinventorysettings.cpp110
-rw-r--r--indra/llinventory/llinventorysettings.h55
-rw-r--r--indra/llinventory/llinventorytype.cpp9
-rw-r--r--indra/llinventory/llinventorytype.h8
-rw-r--r--indra/llinventory/llinvtranslationbrdg.h41
-rw-r--r--indra/llinventory/llparcel.h7
-rw-r--r--indra/llinventory/llsettingsbase.cpp587
-rw-r--r--indra/llinventory/llsettingsbase.h375
-rw-r--r--indra/llinventory/llsettingsdaycycle.cpp629
-rw-r--r--indra/llinventory/llsettingsdaycycle.h146
-rw-r--r--indra/llinventory/llsettingssky.cpp955
-rw-r--r--indra/llinventory/llsettingssky.h531
-rw-r--r--indra/llinventory/llsettingswater.cpp226
-rw-r--r--indra/llinventory/llsettingswater.h239
17 files changed, 3930 insertions, 8 deletions
diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt
index 68dd00d880..f1bc28427d 100644
--- a/indra/llinventory/CMakeLists.txt
+++ b/indra/llinventory/CMakeLists.txt
@@ -23,12 +23,17 @@ set(llinventory_SOURCE_FILES
llfoldertype.cpp
llinventory.cpp
llinventorydefines.cpp
+ llinventorysettings.cpp
llinventorytype.cpp
lllandmark.cpp
llnotecard.cpp
llparcel.cpp
llpermissions.cpp
llsaleinfo.cpp
+ llsettingsbase.cpp
+ llsettingsdaycycle.cpp
+ llsettingssky.cpp
+ llsettingswater.cpp
lltransactionflags.cpp
lluserrelations.cpp
)
@@ -41,7 +46,9 @@ set(llinventory_HEADER_FILES
llfoldertype.h
llinventory.h
llinventorydefines.h
+ llinventorysettings.h
llinventorytype.h
+ llinvtranslationbrdg.h
lllandmark.h
llnotecard.h
llparcel.h
@@ -49,6 +56,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/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp
index b0daf639fa..2c8c82a62b 100644
--- a/indra/llinventory/llfoldertype.cpp
+++ b/indra/llinventory/llfoldertype.cpp
@@ -147,7 +147,7 @@ bool LLFolderType::lookupIsEnsembleType(EType folder_type)
// static
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
{
- if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup())
+ if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::BADLOOKUP)
{
LL_WARNS() << "Converting to unknown asset type " << folder_type << LL_ENDL;
}
diff --git a/indra/llinventory/llinventorydefines.h b/indra/llinventory/llinventorydefines.h
index 3881fb1fd7..54562673f3 100644
--- a/indra/llinventory/llinventorydefines.h
+++ b/indra/llinventory/llinventorydefines.h
@@ -81,9 +81,10 @@ public:
II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS = 0x200000,
// Whether a returned object is composed of multiple items.
- II_FLAGS_WEARABLES_MASK = 0xff,
- // Wearables use the low order byte of flags to store the
- // LLWearableType::EType enumeration found in newview/llwearable.h
+ II_FLAGS_SUBTYPE_MASK = 0x0000ff,
+ // Some items like Wearables and settings use the low order byte
+ // of flags to store the sub type of the inventory item.
+ // see LLWearableType::EType enumeration found in newview/llwearable.h
II_FLAGS_PERM_OVERWRITE_MASK = (II_FLAGS_OBJECT_SLAM_PERM |
II_FLAGS_OBJECT_SLAM_SALE |
diff --git a/indra/llinventory/llinventorysettings.cpp b/indra/llinventory/llinventorysettings.cpp
new file mode 100644
index 0000000000..8887c23a6c
--- /dev/null
+++ b/indra/llinventory/llinventorysettings.cpp
@@ -0,0 +1,110 @@
+/**
+* @file llinventorysettings.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 "linden_common.h"
+#include "llinventorysettings.h"
+#include "llinventorytype.h"
+#include "llinventorydefines.h"
+#include "lldictionary.h"
+#include "llsingleton.h"
+#include "llinvtranslationbrdg.h"
+
+//=========================================================================
+namespace {
+ LLTranslationBridge::ptr_t sTranslator;
+}
+
+//=========================================================================
+struct SettingsEntry : public LLDictionaryEntry
+{
+ SettingsEntry(const std::string &name,
+ const std::string& default_new_name,
+ LLInventoryType::EIconName iconName) :
+ LLDictionaryEntry(name),
+ mDefaultNewName(default_new_name),
+ mLabel(name),
+ mIconName(iconName)
+ {
+ std::string transdname = sTranslator->getString(mLabel);
+ if (!transdname.empty())
+ {
+ mLabel = transdname;
+ }
+ }
+
+ std::string mLabel;
+ std::string mDefaultNewName; //keep mLabel for backward compatibility
+ LLInventoryType::EIconName mIconName;
+};
+
+class LLSettingsDictionary : public LLSingleton<LLSettingsDictionary>,
+ public LLDictionary<LLSettingsType::type_e, SettingsEntry>
+{
+ LLSINGLETON(LLSettingsDictionary);
+
+ void initSingleton();
+};
+
+LLSettingsDictionary::LLSettingsDictionary()
+{
+}
+
+void LLSettingsDictionary::initSingleton()
+{
+ addEntry(LLSettingsType::ST_SKY, new SettingsEntry("sky", "New Sky", LLInventoryType::ICONNAME_SETTINGS_SKY));
+ addEntry(LLSettingsType::ST_WATER, new SettingsEntry("water", "New Water", LLInventoryType::ICONNAME_SETTINGS_WATER));
+ addEntry(LLSettingsType::ST_DAYCYCLE, new SettingsEntry("day", "New Day", LLInventoryType::ICONNAME_SETTINGS_DAY));
+ addEntry(LLSettingsType::ST_NONE, new SettingsEntry("none", "New Settings", LLInventoryType::ICONNAME_SETTINGS));
+ addEntry(LLSettingsType::ST_INVALID, new SettingsEntry("invalid", "New Settings", LLInventoryType::ICONNAME_SETTINGS));
+}
+
+//=========================================================================
+
+LLSettingsType::type_e LLSettingsType::fromInventoryFlags(U32 flags)
+{
+ return (LLSettingsType::type_e)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK);
+}
+
+
+LLInventoryType::EIconName LLSettingsType::getIconName(LLSettingsType::type_e type)
+{
+ const SettingsEntry *entry = LLSettingsDictionary::instance().lookup(type);
+ if (!entry)
+ return getIconName(ST_INVALID);
+ return entry->mIconName;
+}
+
+
+void LLSettingsType::initClass(LLTranslationBridge::ptr_t &trans)
+{
+ sTranslator = trans;
+}
+
+void LLSettingsType::cleanupClass()
+{
+ sTranslator.reset();
+}
diff --git a/indra/llinventory/llinventorysettings.h b/indra/llinventory/llinventorysettings.h
new file mode 100644
index 0000000000..fb08190ea9
--- /dev/null
+++ b/indra/llinventory/llinventorysettings.h
@@ -0,0 +1,55 @@
+/**
+* @file llinventorysettings.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_INVENTORY_SETTINGS_H
+#define LL_INVENTORY_SETTINGS_H
+
+#include "llinventorytype.h"
+#include "llinvtranslationbrdg.h"
+
+class LLSettingsType
+{
+public:
+ enum type_e
+ {
+ ST_SKY = 0,
+ ST_WATER = 1,
+ ST_DAYCYCLE = 2,
+
+ ST_INVALID = 255,
+ ST_NONE = -1
+ };
+
+ static type_e fromInventoryFlags(U32 flags);
+ static LLInventoryType::EIconName getIconName(type_e type);
+
+ static void initClass(LLTranslationBridge::ptr_t &trans);
+ static void cleanupClass();
+};
+
+
+#endif
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index d1e6807f52..2b6b53556d 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -85,6 +85,7 @@ LLInventoryDictionary::LLInventoryDictionary()
addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
+ addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS));
}
@@ -145,6 +146,14 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // 47 AT_NONE
LLInventoryType::IT_NONE, // 48 AT_NONE
LLInventoryType::IT_MESH, // 49 AT_MESH
+
+ LLInventoryType::IT_NONE, // 50 AT_RESERVED_1
+ LLInventoryType::IT_NONE, // 51 AT_RESERVED_2
+ LLInventoryType::IT_NONE, // 52 AT_RESERVED_3
+ LLInventoryType::IT_NONE, // 53 AT_RESERVED_4
+ LLInventoryType::IT_NONE, // 54 AT_RESERVED_5
+
+ LLInventoryType::IT_SETTINGS, // 55 AT_SETTINGS
};
// static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index fc3c78cf50..86486373b5 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -64,7 +64,8 @@ public:
IT_MESH = 22,
IT_WIDGET = 23,
IT_PERSON = 24,
- IT_COUNT = 25,
+ IT_SETTINGS = 25,
+ IT_COUNT = 26,
IT_NONE = -1
};
@@ -110,6 +111,11 @@ public:
ICONNAME_LINKFOLDER,
ICONNAME_MESH,
+ ICONNAME_SETTINGS,
+ ICONNAME_SETTINGS_SKY,
+ ICONNAME_SETTINGS_WATER,
+ ICONNAME_SETTINGS_DAY,
+
ICONNAME_INVALID,
ICONNAME_COUNT,
ICONNAME_NONE = -1
diff --git a/indra/llinventory/llinvtranslationbrdg.h b/indra/llinventory/llinvtranslationbrdg.h
new file mode 100644
index 0000000000..fbd887030a
--- /dev/null
+++ b/indra/llinventory/llinvtranslationbrdg.h
@@ -0,0 +1,41 @@
+/**
+* @file llinvtranslationbrdg.h
+* @brief Translation adapter for inventory.
+*
+* $LicenseInfo:firstyear=2002&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2010, 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_TRANSLATIONBRDG_H
+#define LL_TRANSLATIONBRDG_H
+
+class LLTranslationBridge
+{
+public:
+ typedef std::shared_ptr<LLTranslationBridge> ptr_t;
+
+ // clang needs this to be happy
+ virtual ~LLTranslationBridge() {}
+
+ virtual std::string getString(const std::string &xml_desc) = 0;
+};
+
+#endif
diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h
index 135d0ca7b9..6ef389d246 100644
--- a/indra/llinventory/llparcel.h
+++ b/indra/llinventory/llparcel.h
@@ -34,6 +34,7 @@
#include "llpermissions.h"
#include "lltimer.h"
#include "v3math.h"
+#include "llsettingsdaycycle.h"
// Grid out of which parcels taken is stepped every 4 meters.
const F32 PARCEL_GRID_STEP_METERS = 4.f;
@@ -589,8 +590,7 @@ public:
LLUUID getPreviousOwnerID() const { return mPreviousOwnerID; }
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
-
-
+
protected:
LLUUID mID;
LLUUID mOwnerID;
@@ -665,7 +665,8 @@ protected:
BOOL mAllowGroupAVSounds;
BOOL mAllowAnyAVSounds;
-
+ bool mIsDefaultDayCycle;
+
public:
// HACK, make private
S32 mLocalID;
diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
new file mode 100644
index 0000000000..d8e337e231
--- /dev/null
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -0,0 +1,587 @@
+/**
+* @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 F64 BREAK_POINT = 0.5;
+}
+
+//=========================================================================
+std::ostream &operator <<(std::ostream& os, LLSettingsBase &settings)
+{
+ LLSDSerialize::serialize(settings.getSettings(), os, LLSDSerialize::LLSD_NOTATION);
+
+ return os;
+}
+
+//=========================================================================
+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");
+
+//=========================================================================
+LLSettingsBase::LLSettingsBase():
+ mSettings(LLSD::emptyMap()),
+ mDirty(true),
+ mAssetID(),
+ mBlendedFactor(0.0)
+{
+}
+
+LLSettingsBase::LLSettingsBase(const LLSD setting) :
+ mSettings(setting),
+ mDirty(true),
+ mAssetID(),
+ mBlendedFactor(0.0)
+{
+}
+
+//=========================================================================
+void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F64 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, F64 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::TypeUUID:
+ newSettings[key_name] = value.asUUID();
+ break;
+
+// case LLSD::TypeBoolean:
+// case LLSD::TypeString:
+// 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(getSettings(), 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);
+}
+
+bool LLSettingsBase::validate()
+{
+ validation_list_t validations = getValidationList();
+
+ if (!mSettings.has(SETTING_TYPE))
+ {
+ mSettings[SETTING_TYPE] = getSettingType();
+ }
+
+ LLSD result = LLSettingsBase::settingValidation(mSettings, validations);
+
+ if (result["errors"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Validation errors: " << result["errors"] << LL_ENDL;
+ }
+ if (result["warnings"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Validation warnings: " << result["errors"] << LL_ENDL;
+ }
+
+ return result["success"].asBoolean();
+}
+
+LLSD LLSettingsBase::settingValidation(LLSD &settings, validation_list_t &validations)
+{
+ 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);
+ stringset_t validated;
+ stringset_t strip;
+ bool isValid(true);
+ LLSD errors(LLSD::emptyArray());
+ LLSD warnings(LLSD::emptyArray());
+
+ // Fields common to all settings.
+ if (!validateName.verify(settings))
+ {
+ errors.append( LLSD::String("Unable to validate 'name'.") );
+ isValid = false;
+ }
+ validated.insert(validateName.getName());
+
+ if (!validateId.verify(settings))
+ {
+ errors.append( LLSD::String("Unable to validate 'id'.") );
+ isValid = false;
+ }
+ validated.insert(validateId.getName());
+
+ if (!validateHash.verify(settings))
+ {
+ errors.append( LLSD::String("Unable to validate 'hash'.") );
+ isValid = false;
+ }
+ validated.insert(validateHash.getName());
+
+ if (!validateType.verify(settings))
+ {
+ errors.append( LLSD::String("Unable to validate 'type'.") );
+ isValid = false;
+ }
+ validated.insert(validateType.getName());
+
+ // Fields for specific settings.
+ for (auto &test: validations)
+ {
+ if (!test.verify(settings))
+ {
+ std::stringstream errtext;
+
+ errtext << "Settings LLSD fails validation and could not be corrected for '" << test.getName() << "'!\n";
+ errors.append( errtext.str() );
+ isValid = false;
+ }
+ validated.insert(test.getName());
+ }
+
+ // strip extra entries
+ for (LLSD::map_const_iterator itm = settings.beginMap(); itm != settings.endMap(); ++itm)
+ {
+ if (validated.find((*itm).first) == validated.end())
+ {
+ std::stringstream warntext;
+
+ warntext << "Stripping setting '" << (*itm).first << "'";
+ warnings.append( warntext.str() );
+ strip.insert((*itm).first);
+ }
+ }
+
+ for (const std::string &its: strip)
+ {
+ settings.erase(its);
+ }
+
+ return LLSDMap("success", LLSD::Boolean(isValid))
+ ("errors", errors)
+ ("warnings", warnings);
+}
+
+//=========================================================================
+bool LLSettingsBase::Validator::verify(LLSD &data)
+{
+ if (!data.has(mName) || (data.has(mName) && data[mName].isUndefined()))
+ {
+ if (!mDefault.isUndefined())
+ {
+ LL_INFOS("SETTINGS") << "Inserting missing default for '" << mName << "'." << LL_ENDL;
+ data[mName] = mDefault;
+ return true;
+ }
+ if (mRequired)
+ LL_WARNS("SETTINGS") << "Missing required setting '" << mName << "' with no default." << 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)
+{
+ F64 real = value.asReal();
+
+ F64 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(F64 blendf)
+{
+ setPosition(blendf);
+}
+
+F64 LLSettingsBlender::setPosition(F64 blendf)
+{
+ if (blendf >= 1.0)
+ {
+ triggerComplete();
+ return 1.0;
+ }
+ blendf = llclamp(blendf, 0.0, 1.0);
+
+ mTarget->replaceSettings(mInitial->getSettings());
+ if (!mFinal || (mInitial == mFinal) || (blendf == 0.0))
+ { // this is a trivial blend. Results will be identical to the initial.
+ return blendf;
+ }
+ mTarget->blend(mFinal, blendf);
+
+ return blendf;
+}
+
+void LLSettingsBlender::triggerComplete()
+{
+ mTarget->replaceSettings(mFinal->getSettings());
+ LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon
+ mOnFinished(shared_from_this());
+}
+
+//-------------------------------------------------------------------------
+F64 LLSettingsBlenderTimeDelta::calculateBlend(F64 spanpos, F64 spanlen) const
+{
+ return fmod(spanpos, spanlen) / spanlen;
+}
+
+void LLSettingsBlenderTimeDelta::update(F64 timedelta)
+{
+ mTimeSpent += F64Seconds(timedelta);
+
+ if (mTimeSpent > mBlendSpan)
+ {
+ triggerComplete();
+ return;
+ }
+
+ F64 blendf = calculateBlend(mTimeSpent.value(), mBlendSpan.value());
+ // Note no clamp here.
+
+ setPosition(blendf);
+}
diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h
new file mode 100644
index 0000000000..1ef7df79ad
--- /dev/null
+++ b/indra/llinventory/llsettingsbase.h
@@ -0,0 +1,375 @@
+/**
+* @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/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"
+
+#include "llinventorysettings.h"
+
+class LLSettingsBase :
+ public std::enable_shared_from_this<LLSettingsBase>,
+ private boost::noncopyable
+{
+ friend class LLEnvironment;
+ friend class LLSettingsDay;
+
+ friend std::ostream &operator <<(std::ostream& os, LLSettingsBase &settings);
+
+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 std::shared_ptr<LLSettingsBase> ptr_t;
+
+ virtual ~LLSettingsBase() { };
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const = 0;
+
+ virtual LLSettingsType::type_e getSettingTypeValue() 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;
+ mBlendedFactor = 0.0;
+ 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());
+ }
+
+ inline F64 getBlendFactor() const
+ {
+ return mBlendedFactor;
+ }
+
+ // 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, F64 blendf) = 0;
+
+ virtual bool validate();
+
+ virtual ptr_t buildDerivedClone() = 0;
+
+ class Validator
+ {
+ public:
+ typedef boost::function<bool(LLSD &)> verify_pr;
+
+ Validator(std::string name, bool required, LLSD::Type type, verify_pr verify = verify_pr(), LLSD defval = LLSD()) :
+ mName(name),
+ mRequired(required),
+ mType(type),
+ mVerify(verify),
+ mDefault(defval)
+ { }
+
+ 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;
+ LLSD mDefault;
+ };
+ typedef std::vector<Validator> validation_list_t;
+
+ static LLSD settingValidation(LLSD &settings, validation_list_t &validations);
+protected:
+
+ LLSettingsBase();
+ LLSettingsBase(const LLSD setting);
+
+ static LLSD settingValidation(LLSD settings);
+
+ typedef std::set<std::string> stringset_t;
+
+ // combining settings objects. Customize for specific setting types
+ virtual void lerpSettings(const LLSettingsBase &other, F64 mix);
+ LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, F64 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;
+ LLAssetID mAssetID;
+
+ LLSD cloneSettings() const;
+
+ inline void setBlendFactor(F64 blendfactor)
+ {
+ mBlendedFactor = blendfactor;
+ }
+
+private:
+ bool mDirty;
+
+ LLSD combineSDMaps(const LLSD &first, const LLSD &other) const;
+
+ F64 mBlendedFactor;
+};
+
+
+class LLSettingsBlender : public std::enable_shared_from_this<LLSettingsBlender>
+{
+public:
+ typedef std::shared_ptr<LLSettingsBlender> ptr_t;
+ typedef boost::signals2::signal<void(const ptr_t )> finish_signal_t;
+ typedef boost::signals2::connection connection_t;
+
+ LLSettingsBlender(const LLSettingsBase::ptr_t &target,
+ const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting) :
+ mOnFinished(),
+ mTarget(target),
+ mInitial(initsetting),
+ mFinal(endsetting)
+ {
+ if (mInitial)
+ mTarget->replaceSettings(mInitial->getSettings());
+
+ if (!mFinal)
+ mFinal = mInitial;
+ }
+
+ virtual ~LLSettingsBlender() {}
+
+ virtual void reset( LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, F64 /*span*/ = 1.0)
+ {
+ // note: the 'span' reset parameter is unused by the base class.
+ if (!mInitial)
+ LL_WARNS("BLENDER") << "Reseting blender with empty initial setting. Expect badness in the future." << LL_ENDL;
+
+ mInitial = initsetting;
+ mFinal = endsetting;
+
+ if (!mFinal)
+ mFinal = mInitial;
+
+ mTarget->replaceSettings(mInitial->getSettings());
+ }
+
+ LLSettingsBase::ptr_t getTarget() const
+ {
+ return mTarget;
+ }
+
+ LLSettingsBase::ptr_t getInitial() const
+ {
+ return mInitial;
+ }
+
+ LLSettingsBase::ptr_t getFinal() const
+ {
+ return mFinal;
+ }
+
+ connection_t setOnFinished(const finish_signal_t::slot_type &onfinished)
+ {
+ return mOnFinished.connect(onfinished);
+ }
+
+ virtual void update(F64 blendf);
+ virtual F64 setPosition(F64 blendf);
+
+ virtual void switchTrack(S32 trackno, F64 position = -1.0) { /*NoOp*/ }
+
+protected:
+ void triggerComplete();
+
+ finish_signal_t mOnFinished;
+
+ LLSettingsBase::ptr_t mTarget;
+ LLSettingsBase::ptr_t mInitial;
+ LLSettingsBase::ptr_t mFinal;
+};
+
+class LLSettingsBlenderTimeDelta : public LLSettingsBlender
+{
+public:
+ LLSettingsBlenderTimeDelta(const LLSettingsBase::ptr_t &target,
+ const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, F64Seconds seconds) :
+ LLSettingsBlender(target, initsetting, endsetting),
+ mBlendSpan(seconds),
+ mLastUpdate(0.0f),
+ mTimeSpent(0.0f)
+ {
+ mTimeStart = F64Seconds(LLDate::now().secondsSinceEpoch());
+ mLastUpdate = mTimeStart;
+ }
+
+ virtual ~LLSettingsBlenderTimeDelta()
+ {
+ }
+
+ virtual void reset(LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, F64 span = 1.0) override
+ {
+ LLSettingsBlender::reset(initsetting, endsetting, span);
+
+ mBlendSpan.value(span);
+ mTimeStart.value(LLDate::now().secondsSinceEpoch());
+ mLastUpdate = mTimeStart;
+ mTimeSpent.value(0.0f);
+ }
+
+ virtual void update(F64 timedelta) override;
+
+protected:
+ F64 calculateBlend(F64 spanpos, F64 spanlen) const;
+
+ F64Seconds mBlendSpan;
+ F64Seconds mLastUpdate;
+ F64Seconds mTimeSpent;
+ F64Seconds mTimeStart;
+};
+
+
+#endif
diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp
new file mode 100644
index 0000000000..577b12b031
--- /dev/null
+++ b/indra/llinventory/llsettingsdaycycle.cpp
@@ -0,0 +1,629 @@
+/**
+* @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");
+
+ 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_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 S64Seconds LLSettingsDay::MINIMUM_DAYLENGTH(300); // 5 mins
+const S64Seconds LLSettingsDay::DEFAULT_DAYLENGTH(14400); // 4 hours
+const S64Seconds LLSettingsDay::MAXIMUM_DAYLENGTH(604800); // 7 days
+
+const S64Seconds LLSettingsDay::MINIMUM_DAYOFFSET(0);
+const S64Seconds LLSettingsDay::DEFAULT_DAYOFFSET(57600); // +16 hours == -8 hours (SLT time offset)
+const S64Seconds LLSettingsDay::MAXIMUM_DAYOFFSET(86400); // 24 hours
+
+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];
+
+ settings[SETTING_TYPE] = getSettingType();
+
+ std::map<std::string, LLSettingsBase::ptr_t> in_use;
+
+ LLSD tracks(LLSD::emptyArray());
+
+ for (auto &track: mDayTracks)
+ {
+ LLSD trackout(LLSD::emptyArray());
+
+ for (auto &frame: track)
+ {
+ F32 frame_time = frame.first;
+ LLSettingsBase::ptr_t data = frame.second;
+ size_t datahash = data->getHash();
+
+ std::stringstream keyname;
+ keyname << datahash;
+
+ trackout.append(LLSD(LLSDMap(SETTING_KEYKFRAME, LLSD::Real(frame_time))(SETTING_KEYNAME, keyname.str())));
+ in_use[keyname.str()] = data;
+ }
+ tracks.append(trackout);
+ }
+ settings[SETTING_TRACKS] = tracks;
+
+ LLSD frames(LLSD::emptyMap());
+ for (auto &used_frame: in_use)
+ {
+ LLSD framesettings = llsd_clone(used_frame.second->getSettings(),
+ LLSDMap("*", true)(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false));
+
+ frames[used_frame.first] = framesettings;
+ }
+ settings[SETTING_FRAMES] = frames;
+
+ return settings;
+}
+
+bool 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;
+ LLSettingsBase::ptr_t keyframe;
+
+ if (data[SETTING_TYPE].asString() == "sky")
+ {
+ keyframe = buildSky(data);
+ }
+ else if (data[SETTING_TYPE].asString() == "water")
+ {
+ keyframe = buildWater(data);
+ }
+ else
+ {
+ LL_WARNS("DAYCYCLE") << "Unknown child setting type '" << data[SETTING_TYPE].asString() << "' named '" << name << "'" << LL_ENDL;
+ }
+ if (!keyframe)
+ {
+ LL_WARNS("DAYCYCLE") << "Invalid frame data" << LL_ENDL;
+ continue;
+ }
+
+ used[name] = keyframe;
+ }
+
+ bool haswater(false);
+ bool hassky(false);
+
+ 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)
+ {
+ if (i == TRACK_WATER)
+ haswater |= true;
+ else
+ hassky |= true;
+ mDayTracks[i][keyframe] = setting;
+ }
+ }
+ }
+
+ if (!haswater || !hassky)
+ {
+ LL_WARNS("DAYCYCLE") << "Must have at least one water and one sky frame!" << LL_ENDL;
+ return false;
+ }
+ // these are no longer needed and just take up space now.
+ mSettings.erase(SETTING_TRACKS);
+ mSettings.erase(SETTING_FRAMES);
+
+ mInitialized = true;
+ return true;
+}
+
+
+//=========================================================================
+LLSD LLSettingsDay::defaults()
+{
+ LLSD dfltsetting;
+
+ dfltsetting[SETTING_NAME] = "_default_";
+
+ LLSD waterTrack;
+ waterTrack[SETTING_KEYKFRAME] = 0.0f;
+ waterTrack[SETTING_KEYNAME] = "_default_";
+
+ LLSD skyTrack;
+ skyTrack[SETTING_KEYKFRAME] = 0.0f;
+ skyTrack[SETTING_KEYNAME] = "_default_";
+
+ LLSD tracks;
+ tracks.append(LLSDArray(waterTrack));
+ tracks.append(LLSDArray(skyTrack));
+
+ dfltsetting[SETTING_TRACKS] = tracks;
+
+ LLSD frames(LLSD::emptyMap());
+
+ frames["water:_defaults_"] = LLSettingsWater::defaults();
+ frames["sky:_defaults_"] = LLSettingsSky::defaults();
+
+ dfltsetting[SETTING_FRAMES] = frames;
+
+ dfltsetting[SETTING_TYPE] = "daycycle";
+
+ return dfltsetting;
+}
+
+void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 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);
+ }
+
+ S32 framecount(0);
+
+ for (LLSD::array_iterator track = value.beginArray(); track != value.endArray(); ++track)
+ {
+ S32 index = 0;
+ while (index < (*track).size())
+ {
+ LLSD& elem = (*track)[index];
+
+ ++framecount;
+ if (index >= LLSettingsDay::FRAME_MAX)
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ if (!elem.has(LLSettingsDay::SETTING_KEYKFRAME))
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ if (!elem[LLSettingsDay::SETTING_KEYKFRAME].isReal())
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ if (!elem.has(LLSettingsDay::SETTING_KEYNAME) &&
+ !elem.has(LLSettingsDay::SETTING_KEYID))
+ {
+ (*track).erase(index);
+ continue;
+ }
+
+ F32 frame = elem[LLSettingsDay::SETTING_KEYKFRAME].asReal();
+ if ((frame < 0.0) || (frame > 1.0))
+ {
+ frame = llclamp(frame, 0.0f, 1.0f);
+ elem[LLSettingsDay::SETTING_KEYKFRAME] = frame;
+ }
+ ++index;
+ }
+
+ }
+
+ int waterTracks = value[0].size();
+ int skyTracks = framecount - waterTracks;
+
+ if (waterTracks < 1)
+ {
+ LL_WARNS("SETTINGS") << "Missing water track" << LL_ENDL;
+ return false;
+ }
+
+ if (skyTracks < 1)
+ {
+ LL_WARNS("SETTINGS") << "Missing sky tracks" << LL_ENDL;
+ return false;
+ }
+ return true;
+ }
+
+ bool validateDayCycleFrames(LLSD &value)
+ {
+ bool hasSky(false);
+ bool hasWater(false);
+
+ for (LLSD::map_iterator itf = value.beginMap(); itf != value.endMap(); ++itf)
+ {
+ LLSD frame = (*itf).second;
+
+ std::string ftype = frame[LLSettingsBase::SETTING_TYPE];
+ if (ftype == "sky")
+ {
+ LLSettingsSky::validation_list_t valid_sky = LLSettingsSky::validationList();
+ LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky);
+
+ if (res_sky["success"].asInteger() == 0)
+ {
+ LL_WARNS("SETTINGS") << "Sky setting named '" << (*itf).first << "' validation failed!: " << res_sky << LL_ENDL;
+ LL_WARNS("SETTINGS") << "Sky: " << frame << LL_ENDL;
+ continue;
+ }
+ hasSky |= true;
+ }
+ else if (ftype == "water")
+ {
+ LLSettingsWater::validation_list_t valid_h2o = LLSettingsWater::validationList();
+ LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o);
+ if (res_h2o["success"].asInteger() == 0)
+ {
+ LL_WARNS("SETTINGS") << "Water setting named '" << (*itf).first << "' validation failed!: " << res_h2o << LL_ENDL;
+ LL_WARNS("SETTINGS") << "Water: " << frame << LL_ENDL;
+ continue;
+ }
+ hasWater |= true;
+ }
+ else
+ {
+ LL_WARNS("SETTINGS") << "Unknown settings block of type '" << ftype << "' named '" << (*itf).first << "'" << LL_ENDL;
+ return false;
+ }
+ }
+
+ if (!hasSky)
+ {
+ LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL;
+ return false;
+ }
+
+ if (!hasWater)
+ {
+ LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL;
+ return false;
+ }
+
+ return true;
+ }
+}
+
+LLSettingsDay::validation_list_t LLSettingsDay::getValidationList() const
+{
+ return LLSettingsDay::validationList();
+}
+
+LLSettingsDay::validation_list_t LLSettingsDay::validationList()
+{
+ static validation_list_t validation;
+
+ if (validation.empty())
+ {
+ validation.push_back(Validator(SETTING_TRACKS, true, LLSD::TypeArray,
+ &validateDayCycleTrack));
+ validation.push_back(Validator(SETTING_FRAMES, true, LLSD::TypeMap,
+ &validateDayCycleFrames));
+ }
+
+ return validation;
+}
+
+LLSettingsDay::CycleTrack_t &LLSettingsDay::getCycleTrack(S32 track)
+{
+ static CycleTrack_t emptyTrack;
+ if (mDayTracks.size() <= track)
+ return emptyTrack;
+
+ return mDayTracks[track];
+}
+
+//=========================================================================
+void LLSettingsDay::startDayCycle()
+{
+ F64Seconds now(LLDate::now().secondsSinceEpoch());
+
+ if (!mInitialized)
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to start day cycle on uninitialized object." << LL_ENDL;
+ return;
+ }
+
+}
+
+
+void LLSettingsDay::updateSettings()
+{
+}
+
+//=========================================================================
+LLSettingsDay::KeyframeList_t LLSettingsDay::getTrackKeyframes(S32 trackno)
+{
+ if ((trackno < 0) || (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 (auto &frame: track)
+ {
+ keyframes.push_back(frame.first);
+ }
+
+ return keyframes;
+}
+
+bool LLSettingsDay::moveTrackKeyframe(S32 trackno, F32 old_frame, F32 new_frame)
+{
+ if ((trackno < 0) || (trackno >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL;
+ return false;
+ }
+
+ if (old_frame == new_frame)
+ {
+ return false;
+ }
+
+ CycleTrack_t &track = mDayTracks[trackno];
+ CycleTrack_t::iterator iter = track.find(old_frame);
+ if (iter != track.end())
+ {
+ LLSettingsBase::ptr_t base = iter->second;
+ track.erase(iter);
+ track[llclamp(new_frame, 0.0f, 1.0f)] = base;
+ return true;
+ }
+
+ return false;
+
+}
+
+bool LLSettingsDay::removeTrackKeyframe(S32 trackno, F32 frame)
+{
+ if ((trackno < 0) || (trackno >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL;
+ return false;
+ }
+
+ CycleTrack_t &track = mDayTracks[trackno];
+ CycleTrack_t::iterator iter = track.find(frame);
+ if (iter != track.end())
+ {
+ LLSettingsBase::ptr_t base = iter->second;
+ track.erase(iter);
+ return true;
+ }
+
+ return false;
+}
+
+void LLSettingsDay::setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, F32 keyframe)
+{
+ setSettingsAtKeyframe(water, keyframe, TRACK_WATER);
+}
+
+LLSettingsWater::ptr_t LLSettingsDay::getWaterAtKeyframe(F32 keyframe) const
+{
+ return std::dynamic_pointer_cast<LLSettingsWater>(getSettingsAtKeyframe(keyframe, TRACK_WATER));
+}
+
+void LLSettingsDay::setSkyAtKeyframe(const LLSettingsSky::ptr_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;
+ }
+
+ setSettingsAtKeyframe(sky, keyframe, track);
+}
+
+LLSettingsSky::ptr_t LLSettingsDay::getSkyAtKeyframe(F32 keyframe, S32 track) const
+{
+ if ((track < 1) || (track >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL;
+ return LLSettingsSky::ptr_t();
+ }
+
+ return std::dynamic_pointer_cast<LLSettingsSky>(getSettingsAtKeyframe(keyframe, track));
+}
+
+void LLSettingsDay::setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, F32 keyframe, S32 track)
+{
+ if ((track < 0) || (track >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to set track (#" << track << ") out of range!" << LL_ENDL;
+ return;
+ }
+
+ mDayTracks[track][llclamp(keyframe, 0.0f, 1.0f)] = settings;
+ setDirtyFlag(true);
+}
+
+LLSettingsBase::ptr_t LLSettingsDay::getSettingsAtKeyframe(F32 keyframe, S32 track) const
+{
+ if ((track < 0) || (track >= TRACK_MAX))
+ {
+ LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL;
+ return LLSettingsBase::ptr_t();
+ }
+
+ // todo: better way to identify keyframes?
+ CycleTrack_t::const_iterator iter = mDayTracks[track].find(keyframe);
+ if (iter != mDayTracks[track].end())
+ {
+ return iter->second;
+ }
+
+ return LLSettingsBase::ptr_t();
+}
+
+F32 LLSettingsDay::getUpperBoundFrame(S32 track, F32 keyframe)
+{
+ return get_wrapping_atafter(mDayTracks[track], keyframe)->first;
+}
+
+F32 LLSettingsDay::getLowerBoundFrame(S32 track, F32 keyframe)
+{
+ return get_wrapping_atbefore(mDayTracks[track], keyframe)->first;
+}
+
+LLSettingsDay::TrackBound_t LLSettingsDay::getBoundingEntries(LLSettingsDay::CycleTrack_t &track, F32 keyframe)
+{
+ return TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe));
+}
+
+//=========================================================================
diff --git a/indra/llinventory/llsettingsdaycycle.h b/indra/llinventory/llsettingsdaycycle.h
new file mode 100644
index 0000000000..5e6fc7f21d
--- /dev/null
+++ b/indra/llinventory/llsettingsdaycycle.h
@@ -0,0 +1,146 @@
+/**
+* @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;
+
+// These are alias for LLSettingsWater::ptr_t and LLSettingsSky::ptr_t respectively.
+// Here for definitions only.
+typedef std::shared_ptr<LLSettingsWater> LLSettingsWaterPtr_t;
+typedef std::shared_ptr<LLSettingsSky> LLSettingsSkyPtr_t;
+
+class LLSettingsDay : public LLSettingsBase
+{
+public:
+ 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 S64Seconds MINIMUM_DAYLENGTH;
+ static const S64Seconds DEFAULT_DAYLENGTH;
+ static const S64Seconds MAXIMUM_DAYLENGTH;
+
+ static const S64Seconds MINIMUM_DAYOFFSET;
+ static const S64Seconds DEFAULT_DAYOFFSET;
+ static const S64Seconds MAXIMUM_DAYOFFSET;
+
+ 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 std::shared_ptr<LLSettingsDay> ptr_t;
+ typedef std::vector<F32> KeyframeList_t;
+ typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator> TrackBound_t;
+
+ //---------------------------------------------------------------------
+ LLSettingsDay(const LLSD &data);
+ virtual ~LLSettingsDay() { };
+
+ bool initialize();
+
+ virtual ptr_t buildClone() = 0;
+ virtual LLSD getSettings() const override;
+ virtual LLSettingsType::type_e getSettingTypeValue() const override { return LLSettingsType::ST_DAYCYCLE; }
+
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const override { return std::string("daycycle"); }
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &other, F64 mix) override;
+
+ static LLSD defaults();
+
+ //---------------------------------------------------------------------
+ KeyframeList_t getTrackKeyframes(S32 track);
+ bool moveTrackKeyframe(S32 track, F32 old_frame, F32 new_frame);
+ bool removeTrackKeyframe(S32 track, F32 frame);
+
+ void setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, F32 keyframe);
+ LLSettingsWaterPtr_t getWaterAtKeyframe(F32 keyframe) const;
+ void setSkyAtKeyframe(const LLSettingsSkyPtr_t &sky, F32 keyframe, S32 track);
+ LLSettingsSkyPtr_t getSkyAtKeyframe(F32 keyframe, S32 track) const;
+ void setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, F32 keyframe, S32 track);
+ LLSettingsBase::ptr_t getSettingsAtKeyframe(F32 keyframe, S32 track) const;
+ //---------------------------------------------------------------------
+ void startDayCycle();
+
+ 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; }
+ CycleTrack_t & getCycleTrack(S32 track);
+
+ virtual validation_list_t getValidationList() const override;
+ static validation_list_t validationList();
+
+ virtual LLSettingsBase::ptr_t buildDerivedClone() override { return buildClone(); }
+
+ F32 getUpperBoundFrame(S32 track, F32 keyframe);
+ F32 getLowerBoundFrame(S32 track, F32 keyframe);
+
+protected:
+ LLSettingsDay();
+
+ virtual void updateSettings() override;
+
+ bool mInitialized;
+
+private:
+ CycleList_t mDayTracks;
+
+ F64Seconds mLastUpdateTime;
+
+ 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);
+
+// 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..45c1ca1d7f
--- /dev/null
+++ b/indra/llinventory/llsettingssky.cpp
@@ -0,0 +1,955 @@
+/**
+* @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_BLUE_DENSITY("blue_density");
+const std::string LLSettingsSky::SETTING_BLUE_HORIZON("blue_horizon");
+const std::string LLSettingsSky::SETTING_DENSITY_MULTIPLIER("density_multiplier");
+const std::string LLSettingsSky::SETTING_DISTANCE_MULTIPLIER("distance_multiplier");
+const std::string LLSettingsSky::SETTING_HAZE_DENSITY("haze_density");
+const std::string LLSettingsSky::SETTING_HAZE_HORIZON("haze_horizon");
+
+const std::string LLSettingsSky::SETTING_BLOOM_TEXTUREID("bloom_id");
+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_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_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_TEXTUREID("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");
+
+// these are new settings for the advanced atmospherics model
+const std::string LLSettingsSky::SETTING_PLANET_RADIUS("planet_radius");
+const std::string LLSettingsSky::SETTING_SKY_BOTTOM_RADIUS("sky_bottom_radius");
+const std::string LLSettingsSky::SETTING_SKY_TOP_RADIUS("sky_top_radius");
+const std::string LLSettingsSky::SETTING_SUN_ARC_RADIANS("sun_arc_radians");
+
+const std::string LLSettingsSky::SETTING_RAYLEIGH_CONFIG("rayleigh_config");
+const std::string LLSettingsSky::SETTING_MIE_CONFIG("mie_config");
+const std::string LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR("anisotropy");
+const std::string LLSettingsSky::SETTING_ABSORPTION_CONFIG("absorption_config");
+
+const std::string LLSettingsSky::KEY_DENSITY_PROFILE("density");
+const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH("width");
+const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM("exp_term");
+const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR("exp_scale");
+const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM("linear_term");
+const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM("constant_term");
+
+const LLUUID LLSettingsSky::DEFAULT_SUN_ID("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver
+const LLUUID LLSettingsSky::DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver
+const LLUUID LLSettingsSky::DEFAULT_CLOUD_ID("1dc1368f-e8fe-f02d-a08d-9d9f11c1af6b");
+
+namespace
+{
+
+LLSettingsSky::validation_list_t rayleighValidationList()
+{
+ static LLSettingsBase::validation_list_t rayleighValidation;
+ if (rayleighValidation.empty())
+ {
+ rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
+
+ rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
+
+ rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ }
+ return rayleighValidation;
+}
+
+LLSettingsSky::validation_list_t absorptionValidationList()
+{
+ static LLSettingsBase::validation_list_t absorptionValidation;
+ if (absorptionValidation.empty())
+ {
+ absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
+
+ absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
+
+ absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ }
+ return absorptionValidation;
+}
+
+LLSettingsSky::validation_list_t mieValidationList()
+{
+ static LLSettingsBase::validation_list_t mieValidation;
+ if (mieValidation.empty())
+ {
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
+
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
+
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
+
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+
+ mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, true, LLSD::TypeReal,
+ boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
+ }
+ return mieValidation;
+}
+
+bool validateRayleighLayers(LLSD &value)
+{
+ LLSettingsSky::validation_list_t rayleighValidations = rayleighValidationList();
+ if (value.isArray())
+ {
+ bool allGood = true;
+ for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf)
+ {
+ LLSD& layerConfig = (*itf);
+ if (layerConfig.type() == LLSD::Type::TypeMap)
+ {
+ if (!validateRayleighLayers(layerConfig))
+ {
+ allGood = false;
+ }
+ }
+ else if (layerConfig.type() == LLSD::Type::TypeArray)
+ {
+ return validateRayleighLayers(layerConfig);
+ }
+ else
+ {
+ return LLSettingsBase::settingValidation(value, rayleighValidations);
+ }
+ }
+ return allGood;
+ }
+ llassert(value.type() == LLSD::Type::TypeMap);
+ LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations);
+ if (result["errors"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Rayleigh Config Validation errors: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ if (result["warnings"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Rayleigh Config Validation warnings: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+bool validateAbsorptionLayers(LLSD &value)
+{
+ LLSettingsBase::validation_list_t absorptionValidations = absorptionValidationList();
+ if (value.isArray())
+ {
+ bool allGood = true;
+ for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf)
+ {
+ LLSD& layerConfig = (*itf);
+ if (layerConfig.type() == LLSD::Type::TypeMap)
+ {
+ if (!validateAbsorptionLayers(layerConfig))
+ {
+ allGood = false;
+ }
+ }
+ else if (layerConfig.type() == LLSD::Type::TypeArray)
+ {
+ return validateAbsorptionLayers(layerConfig);
+ }
+ else
+ {
+ return LLSettingsBase::settingValidation(value, absorptionValidations);
+ }
+ }
+ return allGood;
+ }
+ llassert(value.type() == LLSD::Type::TypeMap);
+ LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations);
+ if (result["errors"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Absorption Config Validation errors: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ if (result["warnings"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Absorption Config Validation warnings: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+bool validateMieLayers(LLSD &value)
+{
+ LLSettingsBase::validation_list_t mieValidations = mieValidationList();
+ if (value.isArray())
+ {
+ bool allGood = true;
+ for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf)
+ {
+ LLSD& layerConfig = (*itf);
+ if (layerConfig.type() == LLSD::Type::TypeMap)
+ {
+ if (!validateMieLayers(layerConfig))
+ {
+ allGood = false;
+ }
+ }
+ else if (layerConfig.type() == LLSD::Type::TypeArray)
+ {
+ return validateMieLayers(layerConfig);
+ }
+ else
+ {
+ return LLSettingsBase::settingValidation(value, mieValidations);
+ }
+ }
+ return allGood;
+ }
+ LLSD result = LLSettingsBase::settingValidation(value, mieValidations);
+ if (result["errors"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Mie Config Validation errors: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ if (result["warnings"].size() > 0)
+ {
+ LL_WARNS("SETTINGS") << "Mie Config Validation warnings: " << result["errors"] << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+}
+
+//=========================================================================
+LLSettingsSky::LLSettingsSky(const LLSD &data) :
+ LLSettingsBase(data),
+ mNextSunTextureId(),
+ mNextMoonTextureId(),
+ mNextCloudTextureId()
+{
+}
+
+LLSettingsSky::LLSettingsSky():
+ LLSettingsBase(),
+ mNextSunTextureId(),
+ mNextMoonTextureId(),
+ mNextCloudTextureId()
+{
+}
+
+void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf)
+{
+ LLSettingsSky::ptr_t other = std::static_pointer_cast<LLSettingsSky>(end);
+ LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+ replaceSettings(blenddata);
+ setBlendFactor(blendf);
+ mNextSunTextureId = other->getSunTextureId();
+ mNextMoonTextureId = other->getMoonTextureId();
+ mNextCloudTextureId = other->getCloudNoiseTextureId();
+}
+
+
+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
+{
+ return LLSettingsSky::validationList();
+}
+
+LLSettingsSky::validation_list_t LLSettingsSky::validationList()
+{
+ 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]]]]]]]]]]
+
+// LEGACY_ATMOSPHERICS
+ 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_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_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_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_BLOOM_TEXTUREID, true, LLSD::TypeUUID));
+ 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_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_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_TEXTUREID, false, LLSD::TypeUUID));
+
+ validation.push_back(Validator(SETTING_PLANET_RADIUS, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
+
+ validation.push_back(Validator(SETTING_SKY_BOTTOM_RADIUS, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
+
+ validation.push_back(Validator(SETTING_SKY_TOP_RADIUS, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
+
+ validation.push_back(Validator(SETTING_SUN_ARC_RADIANS, true, LLSD::TypeReal,
+ boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.1f)))));
+
+ validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers));
+ validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));
+ validation.push_back(Validator(SETTING_MIE_CONFIG, true, LLSD::TypeArray, &validateMieLayers));
+ }
+ return validation;
+}
+
+LLSD LLSettingsSky::rayleighConfigDefault()
+{
+ LLSD dflt_rayleigh;
+ dflt_rayleigh[SETTING_DENSITY_PROFILE_WIDTH] = 0.0f; // 0 -> the entire atmosphere
+ dflt_rayleigh[SETTING_DENSITY_PROFILE_EXP_TERM] = 1.0f;
+ dflt_rayleigh[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = -1.0f / 8000.0f;
+ dflt_rayleigh[SETTING_DENSITY_PROFILE_LINEAR_TERM] = 0.0f;
+ dflt_rayleigh[SETTING_DENSITY_PROFILE_CONSTANT_TERM] = 0.0f;
+ return dflt_rayleigh;
+}
+
+LLSD LLSettingsSky::absorptionConfigDefault()
+{
+// absorption (ozone) has two linear ramping zones
+ LLSD dflt_absorption_layer_a;
+ dflt_absorption_layer_a[SETTING_DENSITY_PROFILE_WIDTH] = 25000.0f; // 0 -> the entire atmosphere
+ dflt_absorption_layer_a[SETTING_DENSITY_PROFILE_EXP_TERM] = 0.0f;
+ dflt_absorption_layer_a[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = 0.0f;
+ dflt_absorption_layer_a[SETTING_DENSITY_PROFILE_LINEAR_TERM] = -1.0f / 25000.0f;
+ dflt_absorption_layer_a[SETTING_DENSITY_PROFILE_CONSTANT_TERM] = -2.0f / 3.0f;
+
+ LLSD dflt_absorption_layer_b;
+ dflt_absorption_layer_b[SETTING_DENSITY_PROFILE_WIDTH] = 0.0f; // 0 -> remainder of the atmosphere
+ dflt_absorption_layer_b[SETTING_DENSITY_PROFILE_EXP_TERM] = 0.0f;
+ dflt_absorption_layer_b[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = 0.0f;
+ dflt_absorption_layer_b[SETTING_DENSITY_PROFILE_LINEAR_TERM] = -1.0f / 15000.0f;
+ dflt_absorption_layer_b[SETTING_DENSITY_PROFILE_CONSTANT_TERM] = 8.0f / 3.0f;
+
+ LLSD dflt_absorption;
+ dflt_absorption.append(dflt_absorption_layer_a);
+ dflt_absorption.append(dflt_absorption_layer_b);
+ return dflt_absorption;
+}
+
+LLSD LLSettingsSky::mieConfigDefault()
+{
+ LLSD dflt_mie;
+ dflt_mie[SETTING_DENSITY_PROFILE_WIDTH] = 0.0f; // 0 -> the entire atmosphere
+ dflt_mie[SETTING_DENSITY_PROFILE_EXP_TERM] = 1.0f;
+ dflt_mie[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = -1.0f / 1200.0f;
+ dflt_mie[SETTING_DENSITY_PROFILE_LINEAR_TERM] = 0.0f;
+ dflt_mie[SETTING_DENSITY_PROFILE_CONSTANT_TERM] = 0.0f;
+ dflt_mie[SETTING_MIE_ANISOTROPY_FACTOR] = 0.9f;
+ return dflt_mie;
+}
+
+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
+// LEGACY_ATMOSPHERICS
+ 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_DENSITY_MULTIPLIER] = LLSD::Real(0.0001);
+ dfltsetting[SETTING_DISTANCE_MULTIPLIER] = LLSD::Real(0.8000);
+ dfltsetting[SETTING_HAZE_DENSITY] = LLSD::Real(0.6999);
+ dfltsetting[SETTING_HAZE_HORIZON] = LLSD::Real(0.1899);
+
+ 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_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_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] = IMG_BLOOM1;
+ dfltsetting[SETTING_CLOUD_TEXTUREID] = DEFAULT_CLOUD_ID;
+ dfltsetting[SETTING_MOON_TEXTUREID] = DEFAULT_MOON_ID; // gMoonTextureID; // These two are returned by the login... wow!
+ dfltsetting[SETTING_SUN_TEXTUREID] = DEFAULT_SUN_ID; // gSunTextureID;
+
+ dfltsetting[SETTING_TYPE] = "sky";
+
+ // defaults are for earth...
+ dfltsetting[SETTING_PLANET_RADIUS] = 6360.0f;
+ dfltsetting[SETTING_SKY_BOTTOM_RADIUS] = 6360.0f;
+ dfltsetting[SETTING_SKY_TOP_RADIUS] = 6420.0f;
+ dfltsetting[SETTING_SUN_ARC_RADIANS] = 0.00935f / 2.0f;
+
+ // These are technically capable of handling multiple layers of density config
+ // and so are expected to be an array, but we make an array of size 1 w/ each default density config
+ dfltsetting[SETTING_RAYLEIGH_CONFIG].append(rayleighConfigDefault());
+ dfltsetting[SETTING_MIE_CONFIG].append(mieConfigDefault());
+ dfltsetting[SETTING_ABSORPTION_CONFIG].append(absorptionConfigDefault());
+
+ return dfltsetting;
+}
+
+LLSD LLSettingsSky::translateLegacySettings(LLSD legacy)
+{
+ LLSD newsettings(defaults());
+
+// AdvancedAtmospherics TODO
+// These need to be translated into density profile info in the new settings format...
+// LEGACY_ATMOSPHERICS
+ 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_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_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_RAYLEIGH_CONFIG))
+ {
+ newsettings[SETTING_RAYLEIGH_CONFIG].append(rayleighConfigDefault());
+ }
+
+ if (!legacy.has(SETTING_ABSORPTION_CONFIG))
+ {
+ newsettings[SETTING_ABSORPTION_CONFIG].append(absorptionConfigDefault());
+ }
+
+ if (!legacy.has(SETTING_MIE_CONFIG))
+ {
+ newsettings[SETTING_MIE_CONFIG].append(mieConfigDefault());
+ }
+
+ 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_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_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_PLANET_RADIUS))
+ {
+ newsettings[SETTING_PLANET_RADIUS] = LLSD::Real(legacy[SETTING_PLANET_RADIUS].asReal());
+ }
+ else
+ {
+ newsettings[SETTING_PLANET_RADIUS] = 6360.0f;
+ }
+
+ if (legacy.has(SETTING_SKY_BOTTOM_RADIUS))
+ {
+ newsettings[SETTING_SKY_BOTTOM_RADIUS] = LLSD::Real(legacy[SETTING_SKY_BOTTOM_RADIUS].asReal());
+ }
+ else
+ {
+ newsettings[SETTING_SKY_BOTTOM_RADIUS] = 6360.0f;
+ }
+
+ if (legacy.has(SETTING_SKY_TOP_RADIUS))
+ {
+ newsettings[SETTING_SKY_TOP_RADIUS] = LLSD::Real(legacy[SETTING_SKY_TOP_RADIUS].asReal());
+ }
+ else
+ {
+ newsettings[SETTING_SKY_TOP_RADIUS] = 6420.0f;
+ }
+
+ if (legacy.has(SETTING_SUN_ARC_RADIANS))
+ {
+ newsettings[SETTING_SUN_ARC_RADIANS] = LLSD::Real(legacy[SETTING_SUN_ARC_RADIANS].asReal());
+ }
+ else
+ {
+ newsettings[SETTING_SUN_ARC_RADIANS] = 0.00935f / 2.0f;
+ }
+
+ 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()
+{
+
+// LEGACY_ATMOSPHERICS
+ 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);
+ if (body_az[1] < 0.0f)
+ azimuth = F_TWO_PI - azimuth;
+ }
+ else
+ azimuth = 0.0f;
+
+ if (fabs(body_al.normalize()) > 0.001)
+ {
+ altitude = angle_between(DUE_EAST, body_al);
+ if (body_al[2] < 0.0f)
+ {
+ altitude = F_TWO_PI - altitude;
+ }
+ }
+ else
+ altitude = 0.0f;
+ }
+}
+
+
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
new file mode 100644
index 0000000000..9379cd37c3
--- /dev/null
+++ b/indra/llinventory/llsettingssky.h
@@ -0,0 +1,531 @@
+/**
+* @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_DENSITY_MULTIPLIER;
+ static const std::string SETTING_DISTANCE_MULTIPLIER;
+ static const std::string SETTING_HAZE_DENSITY;
+ static const std::string SETTING_HAZE_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_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_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_TEXTUREID;
+
+ static const std::string SETTING_PLANET_RADIUS;
+ static const std::string SETTING_SKY_BOTTOM_RADIUS;
+ static const std::string SETTING_SKY_TOP_RADIUS;
+ static const std::string SETTING_SUN_ARC_RADIANS;
+
+ static const std::string SETTING_RAYLEIGH_CONFIG;
+ static const std::string SETTING_MIE_CONFIG;
+ static const std::string SETTING_ABSORPTION_CONFIG;
+
+ static const std::string KEY_DENSITY_PROFILE;
+ static const std::string SETTING_DENSITY_PROFILE_WIDTH;
+ static const std::string SETTING_DENSITY_PROFILE_EXP_TERM;
+ static const std::string SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR;
+ static const std::string SETTING_DENSITY_PROFILE_LINEAR_TERM;
+ static const std::string SETTING_DENSITY_PROFILE_CONSTANT_TERM;
+ static const std::string SETTING_MIE_ANISOTROPY_FACTOR;
+
+ static const LLUUID DEFAULT_SUN_ID;
+ static const LLUUID DEFAULT_MOON_ID;
+ static const LLUUID DEFAULT_CLOUD_ID;
+
+ typedef std::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 override { return std::string("sky"); }
+ virtual LLSettingsType::type_e getSettingTypeValue() const override { return LLSettingsType::ST_SKY; }
+
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) override;
+
+ static LLSD defaults();
+
+ LLUUID getBloomTextureId() const
+ {
+ return mSettings[SETTING_BLOOM_TEXTUREID].asUUID();
+ }
+
+ //---------------------------------------------------------------------
+ LLColor3 getAmbientColor() const
+ {
+ return LLColor3(mSettings[SETTING_AMBIENT]);
+ }
+
+ void setAmbientColor(const LLColor3 &val)
+ {
+ setValue(SETTING_AMBIENT, val);
+ }
+
+ 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);
+ }
+
+ 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 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);
+ }
+
+ 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();
+ }
+
+ void setCloudNoiseTextureId(const LLUUID &id)
+ {
+ setValue(SETTING_CLOUD_TEXTUREID, id);
+ }
+
+ 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 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);
+ }
+
+ 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();
+ }
+
+ void setMaxY(F32 val)
+ {
+ setValue(SETTING_MAX_Y, val);
+ }
+
+ 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();
+ }
+
+ void setMoonTextureId(LLUUID id)
+ {
+ setValue(SETTING_MOON_TEXTUREID, id);
+ }
+
+ 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_TEXTUREID].asUUID();
+ }
+
+ void setSunTextureId(LLUUID id)
+ {
+ setValue(SETTING_SUN_TEXTUREID, id);
+ }
+
+ // 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;
+ }
+
+ //=====================================================================
+ virtual void loadTextures() { };
+
+ //=====================================================================
+ virtual validation_list_t getValidationList() const override;
+ static validation_list_t validationList();
+
+ static LLSD translateLegacySettings(LLSD legacy);
+
+ //=====================================================================
+ // transient properties used in animations.
+ LLUUID getNextSunTextureId() const
+ {
+ return mNextSunTextureId;
+ }
+
+ LLUUID getNextMoonTextureId() const
+ {
+ return mNextMoonTextureId;
+ }
+
+ LLUUID getNextCloudNoiseTextureId() const
+ {
+ return mNextCloudTextureId;
+ }
+
+ virtual LLSettingsBase::ptr_t buildDerivedClone() override { return buildClone(); }
+
+protected:
+ 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;
+
+ LLSettingsSky();
+
+ virtual stringset_t getSlerpKeys() const override;
+
+ virtual void updateSettings() override;
+
+private:
+ static LLSD rayleighConfigDefault();
+ static LLSD absorptionConfigDefault();
+ static LLSD mieConfigDefault();
+
+ 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;
+
+ LLUUID mNextSunTextureId;
+ LLUUID mNextMoonTextureId;
+ LLUUID mNextCloudTextureId;
+
+ 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..c6798945a3
--- /dev/null
+++ b/indra/llinventory/llsettingswater.cpp
@@ -0,0 +1,226 @@
+/**
+* @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),
+ mNextNormalMapID()
+{
+}
+
+LLSettingsWater::LLSettingsWater() :
+ LLSettingsBase(),
+ mNextNormalMapID()
+{
+}
+
+//=========================================================================
+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();
+
+ dfltsetting[SETTING_TYPE] = "water";
+
+ 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, F64 blendf)
+{
+ LLSettingsWater::ptr_t other = std::static_pointer_cast<LLSettingsWater>(end);
+ LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, blendf);
+
+ replaceSettings(blenddata);
+ setBlendFactor(blendf);
+ mNextNormalMapID = other->getNormalMapID();
+}
+
+LLSettingsWater::validation_list_t LLSettingsWater::getValidationList() const
+{
+ return LLSettingsWater::validationList();
+}
+
+LLSettingsWater::validation_list_t LLSettingsWater::validationList()
+{
+ 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..acae903e92
--- /dev/null
+++ b/indra/llinventory/llsettingswater.h
@@ -0,0 +1,239 @@
+/**
+* @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 std::shared_ptr<LLSettingsWater> ptr_t;
+
+ //---------------------------------------------------------------------
+ LLSettingsWater(const LLSD &data);
+ virtual ~LLSettingsWater() { };
+
+ virtual ptr_t buildClone() = 0;
+
+ //---------------------------------------------------------------------
+ virtual std::string getSettingType() const override { return std::string("water"); }
+ virtual LLSettingsType::type_e getSettingTypeValue() const override { return LLSettingsType::ST_WATER; }
+
+ // Settings status
+ virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) override;
+
+ 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;
+ }
+
+ //-------------------------------------------
+ LLUUID getNextNormalMapID() const
+ {
+ return mNextNormalMapID;
+ }
+
+
+ virtual validation_list_t getValidationList() const override;
+ static validation_list_t validationList();
+
+ static LLSD translateLegacySettings(LLSD legacy);
+
+ virtual LLSettingsBase::ptr_t buildDerivedClone() override { return buildClone(); }
+
+protected:
+ 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;
+
+ LLSettingsWater();
+
+ LLVector4 mWaterPlane;
+ F32 mWaterFogKS;
+
+private:
+ LLUUID mNextNormalMapID;
+};
+
+#endif