diff options
Diffstat (limited to 'indra/llinventory')
-rw-r--r-- | indra/llinventory/CMakeLists.txt | 11 | ||||
-rw-r--r-- | indra/llinventory/llfoldertype.cpp | 2 | ||||
-rw-r--r-- | indra/llinventory/llinventorydefines.h | 7 | ||||
-rw-r--r-- | indra/llinventory/llinventorysettings.cpp | 110 | ||||
-rw-r--r-- | indra/llinventory/llinventorysettings.h | 55 | ||||
-rw-r--r-- | indra/llinventory/llinventorytype.cpp | 9 | ||||
-rw-r--r-- | indra/llinventory/llinventorytype.h | 8 | ||||
-rw-r--r-- | indra/llinventory/llinvtranslationbrdg.h | 41 | ||||
-rw-r--r-- | indra/llinventory/llparcel.h | 7 | ||||
-rw-r--r-- | indra/llinventory/llsettingsbase.cpp | 587 | ||||
-rw-r--r-- | indra/llinventory/llsettingsbase.h | 375 | ||||
-rw-r--r-- | indra/llinventory/llsettingsdaycycle.cpp | 629 | ||||
-rw-r--r-- | indra/llinventory/llsettingsdaycycle.h | 146 | ||||
-rw-r--r-- | indra/llinventory/llsettingssky.cpp | 955 | ||||
-rw-r--r-- | indra/llinventory/llsettingssky.h | 531 | ||||
-rw-r--r-- | indra/llinventory/llsettingswater.cpp | 226 | ||||
-rw-r--r-- | indra/llinventory/llsettingswater.h | 239 |
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 ¶m) 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 |