diff options
Diffstat (limited to 'indra/llinventory')
| -rw-r--r-- | indra/llinventory/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | indra/llinventory/llfoldertype.cpp | 4 | ||||
| -rw-r--r-- | indra/llinventory/llfoldertype.h | 2 | ||||
| -rw-r--r-- | indra/llinventory/llinventorydefines.h | 7 | ||||
| -rw-r--r-- | indra/llinventory/llinventorysettings.cpp | 116 | ||||
| -rw-r--r-- | indra/llinventory/llinventorysettings.h | 56 | ||||
| -rw-r--r-- | indra/llinventory/llinventorytype.cpp | 15 | ||||
| -rw-r--r-- | indra/llinventory/llinventorytype.h | 10 | ||||
| -rw-r--r-- | indra/llinventory/llinvtranslationbrdg.h | 41 | ||||
| -rw-r--r-- | indra/llinventory/llparcel.cpp | 3 | ||||
| -rw-r--r-- | indra/llinventory/llparcel.h | 20 | ||||
| -rw-r--r-- | indra/llinventory/llsettingsbase.cpp | 751 | ||||
| -rw-r--r-- | indra/llinventory/llsettingsbase.h | 518 | ||||
| -rw-r--r-- | indra/llinventory/llsettingsdaycycle.cpp | 896 | ||||
| -rw-r--r-- | indra/llinventory/llsettingsdaycycle.h | 154 | ||||
| -rw-r--r-- | indra/llinventory/llsettingssky.cpp | 1757 | ||||
| -rw-r--r-- | indra/llinventory/llsettingssky.h | 374 | ||||
| -rw-r--r-- | indra/llinventory/llsettingswater.cpp | 304 | ||||
| -rw-r--r-- | indra/llinventory/llsettingswater.h | 249 | 
19 files changed, 5280 insertions, 8 deletions
| diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt index 32a83a88d9..e829788c91 100644 --- a/indra/llinventory/CMakeLists.txt +++ b/indra/llinventory/CMakeLists.txt @@ -22,12 +22,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      ) @@ -39,7 +44,9 @@ set(llinventory_HEADER_FILES      llfoldertype.h      llinventory.h      llinventorydefines.h +    llinventorysettings.h      llinventorytype.h +    llinvtranslationbrdg.h      lllandmark.h      llnotecard.h      llparcel.h @@ -47,6 +54,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..7241b3c0c2 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -100,6 +100,8 @@ LLFolderDictionary::LLFolderDictionary()  	addEntry(LLFolderType::FT_MARKETPLACE_STOCK,    new FolderEntry("stock",    FALSE));  	addEntry(LLFolderType::FT_MARKETPLACE_VERSION,  new FolderEntry("version",    FALSE)); +    addEntry(LLFolderType::FT_SETTINGS,             new FolderEntry("settings", TRUE)); +  	addEntry(LLFolderType::FT_NONE, 				new FolderEntry("-1",		FALSE));  }; @@ -147,7 +149,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/llfoldertype.h b/indra/llinventory/llfoldertype.h index 515bb05a3f..85b86f9ce5 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -91,6 +91,8 @@ public:  		FT_MARKETPLACE_STOCK = 54,  		FT_MARKETPLACE_VERSION = 55,    // Note: We actually *never* create folders with that type. This is used for icon override only. +        FT_SETTINGS = 56, +  		FT_COUNT,  		FT_NONE = -1 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..fdad50e8d4 --- /dev/null +++ b/indra/llinventory/llinventorysettings.cpp @@ -0,0 +1,116 @@ +/** +* @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; +} + +std::string LLSettingsType::getDefaultName(LLSettingsType::type_e type) +{ +    const SettingsEntry *entry = LLSettingsDictionary::instance().lookup(type); +    if (!entry) +        return getDefaultName(ST_INVALID); +    return entry->mDefaultNewName; +} + +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..906540689c --- /dev/null +++ b/indra/llinventory/llinventorysettings.h @@ -0,0 +1,56 @@ +/** +* @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 std::string getDefaultName(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 7399e1bca4..853ed655f5 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 @@ -200,6 +209,12 @@ bool LLInventoryType::cannotRestrictPermissions(LLInventoryType::EType type)  	}  } +// Should show permissions that apply only to objects rezed in world. +bool LLInventoryType::showInWorldPermissions(LLInventoryType::EType type) +{ +    return (type != IT_SETTINGS); +} +  bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type,  									 LLAssetType::EType asset_type)  { diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 034cee5f45..b6e7fb047f 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_UNKNOWN = 255,  		IT_NONE = -1 @@ -112,6 +113,11 @@ public:  		ICONNAME_LINKFOLDER,  		ICONNAME_MESH, +        ICONNAME_SETTINGS, +        ICONNAME_SETTINGS_SKY, +        ICONNAME_SETTINGS_WATER, +        ICONNAME_SETTINGS_DAY, +  		ICONNAME_INVALID,  		ICONNAME_UNKNOWN,  		ICONNAME_COUNT, @@ -131,6 +137,8 @@ public:  	// true if this type cannot have restricted permissions.  	static bool cannotRestrictPermissions(EType type); +    static bool showInWorldPermissions(EType type); +  private:  	// don't instantiate or derive one of these objects  	LLInventoryType( void ); 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.cpp b/indra/llinventory/llparcel.cpp index 0908613c10..e2469f3c7e 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -231,6 +231,9 @@ void LLParcel::init(const LLUUID &owner_id,  	setAllowGroupAVSounds(TRUE);  	setAllowAnyAVSounds(TRUE);  	setHaveNewParcelLimitData(FALSE); + +    setRegionAllowEnvironmentOverride(FALSE); +    setParcelEnvironmentVersion(INVALID_PARCEL_ENVIRONMENT_VERSION);  }  void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned) diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 135d0ca7b9..3b39aeb56b 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; @@ -102,6 +103,10 @@ const U32 RT_SELL	= 0x1 << 5;  const S32 INVALID_PARCEL_ID = -1; +const S32 INVALID_PARCEL_ENVIRONMENT_VERSION = -2; +// if Region settings are used, parcel env. version is -1 +const S32 UNSET_PARCEL_ENVIRONMENT_VERSION = -1; +  // Timeouts for parcels  // default is 21 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 1814400000000  const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(1814400000000); @@ -510,6 +515,10 @@ public:  					{ return mRegionDenyAgeUnverifiedOverride; }      BOOL    getRegionAllowAccessOverride() const                      { return mRegionAllowAccessoverride; } +    BOOL    getRegionAllowEnvironmentOverride() const +                    { return mRegionAllowEnvironmentOverride; } +    S32     getParcelEnvironmentVersion() const  +                    { return mCurrentEnvironmentVersion; }  	BOOL	getAllowGroupAVSounds()	const	{ return mAllowGroupAVSounds;	}  @@ -580,6 +589,9 @@ public:  	void	setRegionDenyAnonymousOverride(BOOL override)	{ mRegionDenyAnonymousOverride = override; }  	void	setRegionDenyAgeUnverifiedOverride(BOOL override)	{ mRegionDenyAgeUnverifiedOverride = override; }      void    setRegionAllowAccessOverride(BOOL override) { mRegionAllowAccessoverride = override; } +    void    setRegionAllowEnvironmentOverride(BOOL override) { mRegionAllowEnvironmentOverride = override; } + +    void    setParcelEnvironmentVersion(S32 version) { mCurrentEnvironmentVersion = version; }  	// Accessors for parcel sellWithObjects  	void	setPreviousOwnerID(LLUUID prev_owner)	{ mPreviousOwnerID = prev_owner; } @@ -589,8 +601,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; @@ -662,10 +673,13 @@ protected:  	BOOL				mRegionDenyAnonymousOverride;  	BOOL				mRegionDenyAgeUnverifiedOverride;      BOOL                mRegionAllowAccessoverride; +    BOOL                mRegionAllowEnvironmentOverride;  	BOOL				mAllowGroupAVSounds;  	BOOL				mAllowAnyAVSounds; +    S32                 mCurrentEnvironmentVersion; -	 +    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..61b59e35aa --- /dev/null +++ b/indra/llinventory/llsettingsbase.cpp @@ -0,0 +1,751 @@ +/** +* @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 LLSettingsBase::TrackPosition BREAK_POINT = 0.5; +} + +const LLSettingsBase::TrackPosition LLSettingsBase::INVALID_TRACKPOS(-1.0); +const std::string LLSettingsBase::DEFAULT_SETTINGS_NAME("_default_"); + +//========================================================================= +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"); +const std::string LLSettingsBase::SETTING_ASSETID("asset_id"); +const std::string LLSettingsBase::SETTING_FLAGS("flags"); + +const U32 LLSettingsBase::FLAG_NOCOPY(0x01 << 0); +const U32 LLSettingsBase::FLAG_NOMOD(0x01 << 1); +const U32 LLSettingsBase::FLAG_NOTRANS(0x01 << 2); +const U32 LLSettingsBase::FLAG_NOSAVE(0x01 << 3); + +const U32 LLSettingsBase::Validator::VALIDATION_PARTIAL(0x01 << 0); + +//========================================================================= +LLSettingsBase::LLSettingsBase(): +    mSettings(LLSD::emptyMap()), +    mDirty(true), +    mBlendedFactor(0.0) +{ +} + +LLSettingsBase::LLSettingsBase(const LLSD setting) : +    mSettings(setting), +    mDirty(true), +    mBlendedFactor(0.0) +{ +} + +//========================================================================= +void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F64 mix)  +{ +    mSettings = interpolateSDMap(mSettings, other.mSettings, other.getParameterMap(), 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, const parammapping_t& defaults, F64 mix) const +{ +    LLSD newSettings; + +    stringset_t skip = getSkipInterpolateKeys(); +    stringset_t slerps = getSlerpKeys(); + +    llassert(mix >= 0.0f && mix <= 1.0f); + +    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; + +        LLSD other_value; +        if (other.has(key_name)) +        { +            other_value = other[key_name]; +        } +        else +        { +            parammapping_t::const_iterator def_iter = defaults.find(key_name); +            if (def_iter != defaults.end()) +            { +                other_value = def_iter->second.getDefaultValue(); +            } +            else if (value.type() == LLSD::TypeMap) +            { +                // interpolate in case there are defaults inside (part of legacy) +                other_value = LLSDMap(); +            } +            else +            { +                // The other or defaults does not contain this setting, keep the original value  +                // TODO: Should I blend this out instead? +                newSettings[key_name] = value; +                continue; +            } +        } + +        newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, slerps); +    } + +    // Special handling cases +    // Flags +    if (settings.has(SETTING_FLAGS)) +    { +        U32 flags = (U32)settings[SETTING_FLAGS].asInteger(); +        if (other.has(SETTING_FLAGS)) +            flags |= (U32)other[SETTING_FLAGS].asInteger(); + +        newSettings[SETTING_FLAGS] = LLSD::Integer(flags); +    } + +    // Now add anything that is in other but not in the settings +    for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it) +    { +        std::string key_name = (*it).first; + +        if (skip.find(key_name) != skip.end()) +            continue; + +        if (settings.has(key_name)) +            continue; + +        parammapping_t::const_iterator def_iter = defaults.find(key_name); +        if (def_iter != defaults.end()) +        { +            // Blend against default value +            newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, slerps); +        } +        else if ((*it).second.type() == LLSD::TypeMap) +        { +            // interpolate in case there are defaults inside (part of legacy) +            newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, slerps); +        } +        // else do nothing when no known defaults +        // TODO: Should I blend this out instead? +    } + +    // Note: writes variables from skip list, bug? +    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::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const +{ +    LLSD new_value; + +    LLSD::Type setting_type = value.type(); + +    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; +        new_value = (mix > BREAK_POINT) ? other_value : value; +    } + +    switch (setting_type) +    { +        case LLSD::TypeInteger: +            // lerp between the two values rounding the result to the nearest integer.  +            new_value = LLSD::Integer(llroundf(lerp(value.asReal(), other_value.asReal(), mix))); +            break; +        case LLSD::TypeReal: +            // lerp between the two values. +            new_value = LLSD::Real(lerp(value.asReal(), other_value.asReal(), mix)); +            break; +        case LLSD::TypeMap: +            // deep copy. +            new_value = interpolateSDMap(value, other_value, defaults, mix); +            break; + +        case LLSD::TypeArray: +        { +            LLSD new_array(LLSD::emptyArray()); + +            if (slerps.find(key_name) != slerps.end()) +            { +                LLQuaternion a(value); +                LLQuaternion b(other_value); +                LLQuaternion q = slerp(mix, a, b); +                new_array = 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) +                { + +                    new_array[i] = lerp(value[i].asReal(), other_value[i].asReal(), mix); +                } +            } + +            new_value = new_array; +        } + +        break; + +        case LLSD::TypeUUID: +            new_value = value.asUUID(); +            break; + +            //      case LLSD::TypeBoolean: +            //      case LLSD::TypeString: +            //      case LLSD::TypeURI: +            //      case LLSD::TypeBinary: +            //      case LLSD::TypeDate: +        default: +            // atomic or unknown data types. Lerping between them does not make sense so switch at the break. +            new_value = (mix > BREAK_POINT) ? other_value : value; +            break; +    } + +    return new_value; +} + +LLSettingsBase::stringset_t LLSettingsBase::getSkipInterpolateKeys() const +{ +    static stringset_t skipSet; + +    if (skipSet.empty()) +    { +        skipSet.insert(SETTING_FLAGS); +        skipSet.insert(SETTING_HASH); +    } + +    return skipSet; +} + +LLSD LLSettingsBase::getSettings() const +{ +    return mSettings; +} + +LLSD LLSettingsBase::cloneSettings() const +{ +    U32 flags = getFlags(); +    LLSD settings (combineSDMaps(getSettings(), LLSD())); +    if (flags) +        settings[SETTING_FLAGS] = LLSD::Integer(flags); +    return settings; +} + +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)); + +    boost::hash<LLSD> hasher; +    return hasher(hash_settings); +} + +bool LLSettingsBase::validate() +{ +    validation_list_t validations = getValidationList(); + +    if (!mSettings.has(SETTING_TYPE)) +    { +        mSettings[SETTING_TYPE] = getSettingsType(); +    } + +    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_DEBUGS("SETTINGS") << "Validation warnings: " << result["warnings"] << LL_ENDL; +    } + +    return result["success"].asBoolean(); +} + +LLSD LLSettingsBase::settingValidation(LLSD &settings, validation_list_t &validations, bool partial) +{ +    static Validator  validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, 63)); +    static Validator  validateId(SETTING_ID, false, LLSD::TypeUUID); +    static Validator  validateHash(SETTING_HASH, false, LLSD::TypeInteger); +    static Validator  validateType(SETTING_TYPE, false, LLSD::TypeString); +    static Validator  validateAssetId(SETTING_ASSETID, false, LLSD::TypeUUID); +    static Validator  validateFlags(SETTING_FLAGS, false, LLSD::TypeInteger); +    stringset_t       validated; +    stringset_t       strip; +    bool              isValid(true); +    LLSD              errors(LLSD::emptyArray()); +    LLSD              warnings(LLSD::emptyArray()); +    U32               flags(0); +     +    if (partial) +        flags |= Validator::VALIDATION_PARTIAL; + +    // Fields common to all settings. +    if (!validateName.verify(settings, flags)) +    { +        errors.append( LLSD::String("Unable to validate 'name'.") ); +        isValid = false; +    } +    validated.insert(validateName.getName()); + +    if (!validateId.verify(settings, flags)) +    { +        errors.append( LLSD::String("Unable to validate 'id'.") ); +        isValid = false; +    } +    validated.insert(validateId.getName()); + +    if (!validateHash.verify(settings, flags)) +    { +        errors.append( LLSD::String("Unable to validate 'hash'.") ); +        isValid = false; +    } +    validated.insert(validateHash.getName()); + +    if (!validateAssetId.verify(settings, flags)) +    { +        errors.append(LLSD::String("Invalid asset Id")); +        isValid = false; +    } +    validated.insert(validateAssetId.getName()); + +    if (!validateType.verify(settings, flags)) +    { +        errors.append( LLSD::String("Unable to validate 'type'.") ); +        isValid = false; +    } +    validated.insert(validateType.getName()); + +    if (!validateFlags.verify(settings, flags)) +    { +        errors.append(LLSD::String("Unable to validate 'flags'.")); +        isValid = false; +    } +    validated.insert(validateFlags.getName()); + +    // Fields for specific settings. +    for (validation_list_t::iterator itv = validations.begin(); itv != validations.end(); ++itv) +    { +#ifdef VALIDATION_DEBUG +        LLSD oldvalue; +        if (settings.has((*itv).getName())) +        { +            oldvalue = llsd_clone(mSettings[(*itv).getName()]); +        } +#endif + +        if (!(*itv).verify(settings, flags)) +        { +            std::stringstream errtext; + +            errtext << "Settings LLSD fails validation and could not be corrected for '" << (*itv).getName() << "'!\n"; +            errors.append( errtext.str() ); +            isValid = false; +        } +        validated.insert((*itv).getName()); + +#ifdef VALIDATION_DEBUG +        if (!oldvalue.isUndefined()) +        { +            if (!compare_llsd(settings[(*itv).getName()], oldvalue)) +            { +                LL_WARNS("SETTINGS") << "Setting '" << (*itv).getName() << "' was changed: " << oldvalue << " -> " << settings[(*itv).getName()] << LL_ENDL; +            } +        } +#endif +    } + +    // 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 (stringset_t::iterator its = strip.begin(); its != strip.end(); ++its) +    { +        settings.erase(*its); +    } + +    return LLSDMap("success", LLSD::Boolean(isValid)) +        ("errors", errors) +        ("warnings", warnings); +} + +//========================================================================= + +bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags) +{ +    if (!data.has(mName) || (data.has(mName) && data[mName].isUndefined())) +    { +        if ((flags & VALIDATION_PARTIAL) != 0) // we are doing a partial validation.  Do no attempt to set a default if missing (or fail even if required) +            return true;     +         +        if (!mDefault.isUndefined()) +        { +            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; +} + +bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, S32 length) +{ +    std::string sval = value.asString(); + +    if (!sval.empty()) +    { +        sval = sval.substr(0, length); +        value = LLSD::String(sval); +    } +    return true; +} + +//========================================================================= +void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf) +{ +    F64 res = setBlendFactor(blendf); +    llassert(res >= 0.0 && res <= 1.0); +    (void)res; +    mTarget->update(); +} + +F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in) +{ +    LLSettingsBase::TrackPosition blendf = blendf_in; +    if (blendf >= 1.0) +    { +        triggerComplete(); +    } +    blendf = llclamp(blendf, 0.0f, 1.0f); + +    if (mTarget) +    { +        mTarget->replaceSettings(mInitial->getSettings()); +        mTarget->blend(mFinal, blendf); +    } +    else +    { +        LL_WARNS("SETTINGS") << "No target for settings blender." << LL_ENDL; +    } + +    return blendf; +} + +void LLSettingsBlender::triggerComplete() +{ +    if (mTarget) +        mTarget->replaceSettings(mFinal->getSettings()); +    LLSettingsBlender::ptr_t hold = shared_from_this();   // prevents this from deleting too soon +    mTarget->update(); +    mOnFinished(shared_from_this()); +} + +//------------------------------------------------------------------------- +const LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::MIN_BLEND_DELTA(FLT_EPSILON); + +LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const +{ +    return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen); +} + +bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta) +{ +    mTimeSpent += timedelta; + +    if (mTimeSpent > mBlendSpan) +    { +        triggerComplete(); +        return false; +    } + +    LLSettingsBase::BlendFactor blendf = calculateBlend(mTimeSpent, mBlendSpan); + +    if (fabs(mLastBlendF - blendf) < mBlendFMinDelta) +    { +        return false; +    } + +    mLastBlendF = blendf; +    update(blendf); +    return true; +} diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h new file mode 100644 index 0000000000..1d118f0789 --- /dev/null +++ b/indra/llinventory/llsettingsbase.h @@ -0,0 +1,518 @@ +/** +* @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 "llunits.h" + +#include "llinventorysettings.h" + +#define PTR_NAMESPACE     std +#define SETTINGS_OVERRIDE override + +class LLSettingsBase :  +    public PTR_NAMESPACE::enable_shared_from_this<LLSettingsBase>, +    private boost::noncopyable +{ +    friend class LLEnvironment; +    friend class LLSettingsDay; + +    friend std::ostream &operator <<(std::ostream& os, LLSettingsBase &settings); + +protected: +    LOG_CLASS(LLSettingsBase); +public: +    typedef F64Seconds Seconds; +    typedef F64        BlendFactor; +    typedef F32        TrackPosition; // 32-bit as these are stored in LLSD as such +    static const TrackPosition INVALID_TRACKPOS; +    static const std::string DEFAULT_SETTINGS_NAME; + +    static const std::string SETTING_ID; +    static const std::string SETTING_NAME; +    static const std::string SETTING_HASH; +    static const std::string SETTING_TYPE; +    static const std::string SETTING_ASSETID; +    static const std::string SETTING_FLAGS; + +    static const U32 FLAG_NOCOPY; +    static const U32 FLAG_NOMOD; +    static const U32 FLAG_NOTRANS; +    static const U32 FLAG_NOSAVE; + +    class DefaultParam +    { +    public: +        DefaultParam(S32 key, const LLSD& value) : mShaderKey(key), mDefaultValue(value) {} +        DefaultParam() : mShaderKey(-1) {} +        S32 getShaderKey() const { return mShaderKey; } +        const LLSD getDefaultValue() const { return mDefaultValue; } + +    private: +        S32 mShaderKey; +        LLSD mDefaultValue; +    }; +    // Contains settings' names (map key), related shader id-key and default +    // value for revert in case we need to reset shader (no need to search each time) +    typedef std::map<std::string, DefaultParam>  parammapping_t; + +    typedef PTR_NAMESPACE::shared_ptr<LLSettingsBase> ptr_t; + +    virtual ~LLSettingsBase() { }; + +    //--------------------------------------------------------------------- +    virtual std::string getSettingsType() const = 0; + +    virtual LLSettingsType::type_e getSettingsTypeValue() const = 0; + +    //--------------------------------------------------------------------- +    // Settings status  +    inline bool hasSetting(const std::string ¶m) const { return mSettings.has(param); } +    virtual bool isDirty() const { return mDirty; } +    virtual bool isVeryDirty() const { return mReplaced; } +    inline void setDirtyFlag(bool dirty) { mDirty = dirty; clearAssetId(); } + +    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 LLUUID getAssetId() const +    { +        if (mSettings.has(SETTING_ASSETID)) +            return mSettings[SETTING_ASSETID].asUUID(); +        return LLUUID(); +    } + +    inline U32 getFlags() const +    { +        if (mSettings.has(SETTING_FLAGS)) +            return static_cast<U32>(mSettings[SETTING_FLAGS].asInteger()); +        return 0; +    } + +    inline void setFlags(U32 value) +    { +        setLLSD(SETTING_FLAGS, LLSD::Integer(value)); +    } + +    inline bool getFlag(U32 flag) const +    { +        if (mSettings.has(SETTING_FLAGS)) +            return ((U32)mSettings[SETTING_FLAGS].asInteger() & flag) == flag; +        return false; +    } + +    inline void setFlag(U32 flag) +    { +        U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0); + +        flags |= flag; + +        if (flags) +            mSettings[SETTING_FLAGS] = LLSD::Integer(flags); +        else +            mSettings.erase(SETTING_FLAGS); +    } + +    inline void clearFlag(U32 flag) +    { +        U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0); + +        flags &= ~flag; + +        if (flags) +            mSettings[SETTING_FLAGS] = LLSD::Integer(flags); +        else +            mSettings.erase(SETTING_FLAGS); +    } + +    virtual void replaceSettings(LLSD settings) +    { +        mBlendedFactor = 0.0; +        setDirtyFlag(true); +        mReplaced = true; +        mSettings = settings; +    } + +    virtual LLSD getSettings() const; + +    //--------------------------------------------------------------------- +    //  +    inline void setLLSD(const std::string &name, const LLSD &value) +    { +        mSettings[name] = value; +        mDirty = true; +        if (name != SETTING_ASSETID) +            clearAssetId(); +    } + +    inline void setValue(const std::string &name, const LLSD &value) +    { +        setLLSD(name, value); +    } + +    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, F32 v) +    { +        setLLSD(name, LLSD::Real(v)); +    } + +    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 BlendFactor 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) && (!mReplaced)) +            return; +        (const_cast<LLSettingsBase *>(this))->updateSettings(); +    } + +    virtual void    blend(const ptr_t &end, BlendFactor blendf) = 0; + +    virtual bool    validate(); + +    virtual ptr_t   buildDerivedClone() const = 0; + +    class Validator +    { +    public: +        static const U32 VALIDATION_PARTIAL; +         +        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, U32 flags); + +        // 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); +        static bool verifyStringLength(LLSD &value, S32 length); + +    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, bool partial = false); + +    inline void setAssetId(LLUUID value) +    {   // note that this skips setLLSD +        mSettings[SETTING_ASSETID] = value; +    } + +    inline void clearAssetId() +    { +        if (mSettings.has(SETTING_ASSETID)) +            mSettings.erase(SETTING_ASSETID); +    } + +    // Calculate any custom settings that may need to be cached. +    virtual void updateSettings() { mDirty = false; mReplaced = false; } +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, BlendFactor mix); + +    // combining settings maps where it can based on mix rate +    // @settings initial value (mix==0) +    // @other target value (mix==1) +    // @defaults list of default values for legacy fields and (re)setting shaders +    // @mix from 0 to 1, ratio or rate of transition from initial 'settings' to 'other' +    // return interpolated and combined LLSD map +    LLSD    interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix) const; +    LLSD    interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) 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;  + +    // A list of settings that represent quaternions and should be slerped  +    // rather than lerped. +    virtual stringset_t getSlerpKeys() const { return stringset_t(); } + +    virtual validation_list_t getValidationList() const = 0; + +    // Apply any settings that need special handling.  +    virtual void applySpecial(void *, bool force = false) { }; + +    virtual parammapping_t getParameterMap() const { return parammapping_t(); } + +    LLSD        mSettings; +    bool        mIsValid; + +    LLSD        cloneSettings() const; + +    inline void setBlendFactor(BlendFactor blendfactor)  +    { +        mBlendedFactor = blendfactor; +    } + +    void replaceWith(LLSettingsBase::ptr_t other) +    { +        replaceSettings(other->cloneSettings()); +        setBlendFactor(other->getBlendFactor()); +    } + +private: +    bool        mDirty; +    bool        mReplaced; // super dirty! + +    LLSD        combineSDMaps(const LLSD &first, const LLSD &other) const; + +    BlendFactor mBlendedFactor; +}; + + +class LLSettingsBlender : public PTR_NAMESPACE::enable_shared_from_this<LLSettingsBlender> +{ +    LOG_CLASS(LLSettingsBlender); +public: +    typedef PTR_NAMESPACE::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) +            mTarget->replaceSettings(mInitial->getSettings()); + +        if (!mFinal) +            mFinal = mInitial; +    } + +    virtual ~LLSettingsBlender() {} + +    virtual void reset( LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::TrackPosition&) +    { +        // 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; + +        if (mTarget) +            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(const LLSettingsBase::BlendFactor& blendf); +    virtual bool            applyTimeDelta(const LLSettingsBase::Seconds& timedelta) +    { +        llassert(false); +        // your derived class needs to implement an override of this func +        return false; +    } + +    virtual F64             setBlendFactor(const LLSettingsBase::BlendFactor& position); + +    virtual void            switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) { /*NoOp*/ } + +protected: +    void                    triggerComplete(); + +    finish_signal_t         mOnFinished; + +    LLSettingsBase::ptr_t   mTarget; +    LLSettingsBase::ptr_t   mInitial; +    LLSettingsBase::ptr_t   mFinal; +}; + +class LLSettingsBlenderTimeDelta : public LLSettingsBlender +{ +    LOG_CLASS(LLSettingsBlenderTimeDelta); +public: +    static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA; + +    LLSettingsBlenderTimeDelta(const LLSettingsBase::ptr_t &target, +        const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::Seconds& blend_span) : +        LLSettingsBlender(target, initsetting, endsetting), +        mBlendSpan(blend_span), +        mLastUpdate(0.0f), +        mTimeSpent(0.0f), +        mBlendFMinDelta(MIN_BLEND_DELTA), +        mLastBlendF(-1.0f) +    { +        mTimeStart = LLSettingsBase::Seconds(LLDate::now().secondsSinceEpoch()); +        mLastUpdate = mTimeStart; +    } + +    virtual ~LLSettingsBlenderTimeDelta()  +    { +    } + +    virtual void reset(LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::TrackPosition& blend_span) SETTINGS_OVERRIDE +    { +        LLSettingsBlender::reset(initsetting, endsetting, blend_span); + +        mBlendSpan  = blend_span; +        mTimeStart  = LLSettingsBase::Seconds(LLDate::now().secondsSinceEpoch()); +        mLastUpdate = mTimeStart; +        mTimeSpent  = LLSettingsBase::Seconds(0.0f); +        mLastBlendF = LLSettingsBase::BlendFactor(-1.0f); +    } + +    virtual bool applyTimeDelta(const LLSettingsBase::Seconds& timedelta) SETTINGS_OVERRIDE; + +    inline void setTimeSpent(LLSettingsBase::Seconds time) { mTimeSpent = time; } +protected: +    LLSettingsBase::BlendFactor calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const; + +    LLSettingsBase::TrackPosition mBlendSpan; +    LLSettingsBase::Seconds mLastUpdate; +    LLSettingsBase::Seconds mTimeSpent; +    LLSettingsBase::Seconds mTimeStart; +    LLSettingsBase::BlendFactor mBlendFMinDelta; +    LLSettingsBase::BlendFactor mLastBlendF; +}; + + +#endif diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp new file mode 100644 index 0000000000..457e5b7478 --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -0,0 +1,896 @@ +/** +* @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 "llerror.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"); + +    template<typename T> +    inline T get_wrapping_distance(T begin, T end) +    { +        if (begin < end) +        { +            return end - begin; +        } +        else if (begin > end) +        { +            return T(1.0) - (begin - end); +        } + +        return 0; +    } + +    LLSettingsDay::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& 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, const LLSettingsBase::TrackPosition& 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 LLSettingsDay::Seconds LLSettingsDay::MINIMUM_DAYLENGTH(14400);  // 4 hours +const LLSettingsDay::Seconds LLSettingsDay::DEFAULT_DAYLENGTH(14400);  // 4 hours +const LLSettingsDay::Seconds LLSettingsDay::MAXIMUM_DAYLENGTH(604800); // 7 days + +const LLSettingsDay::Seconds LLSettingsDay::MINIMUM_DAYOFFSET(0); +const LLSettingsDay::Seconds LLSettingsDay::DEFAULT_DAYOFFSET(57600);  // +16 hours == -8 hours (SLT time offset) +const LLSettingsDay::Seconds LLSettingsDay::MAXIMUM_DAYOFFSET(86400);  // 24 hours + +const S32 LLSettingsDay::TRACK_WATER(0);   // water track is 0 +const S32 LLSettingsDay::TRACK_GROUND_LEVEL(1); +const S32 LLSettingsDay::TRACK_MAX(5);     // 5 tracks, 4 skys, 1 water +const S32 LLSettingsDay::FRAME_MAX(56); + +const F32 LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR(0.02501f); + +const LLUUID LLSettingsDay::DEFAULT_ASSET_ID("5646d39e-d3d7-6aff-ed71-30fc87d64a91"); + +// Minimum value to prevent multislider in edit floaters from eating up frames that 'encroach' on one another's space +static const F32 DEFAULT_MULTISLIDER_INCREMENT(0.005f); +//========================================================================= +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]; + +    if (mSettings.has(SETTING_ASSETID)) +        settings[SETTING_ASSETID] = mSettings[SETTING_ASSETID]; + +    settings[SETTING_TYPE] = getSettingsType(); + +    std::map<std::string, LLSettingsBase::ptr_t> in_use; + +    LLSD tracks(LLSD::emptyArray()); +     +    for (CycleList_t::const_iterator itTrack = mDayTracks.begin(); itTrack != mDayTracks.end(); ++itTrack) +    { +        LLSD trackout(LLSD::emptyArray()); + +        for (CycleTrack_t::const_iterator itFrame = (*itTrack).begin(); itFrame != (*itTrack).end(); ++itFrame) +        { +            F32 frame = (*itFrame).first; +            LLSettingsBase::ptr_t data = (*itFrame).second; +            size_t datahash = data->getHash(); + +            std::stringstream keyname; +            keyname << datahash; + +            trackout.append(LLSD(LLSDMap(SETTING_KEYKFRAME, LLSD::Real(frame))(SETTING_KEYNAME, keyname.str()))); +            in_use[keyname.str()] = data; +        } +        tracks.append(trackout); +    } +    settings[SETTING_TRACKS] = tracks; + +    LLSD frames(LLSD::emptyMap()); +    for (std::map<std::string, LLSettingsBase::ptr_t>::iterator itFrame = in_use.begin(); itFrame != in_use.end(); ++itFrame) +    { +        LLSD framesettings = llsd_clone((*itFrame).second->getSettings(), +            LLSDMap("*", true)(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)); + +        frames[(*itFrame).first] = framesettings; +    } +    settings[SETTING_FRAMES] = frames; + +    return settings; +} + +bool LLSettingsDay::initialize(bool validate_frames) +{ +    LLSD tracks = mSettings[SETTING_TRACKS]; +    LLSD frames = mSettings[SETTING_FRAMES]; + +    // save for later...  +    LLUUID assetid; +    if (mSettings.has(SETTING_ASSETID)) +    { +        assetid = mSettings[SETTING_ASSETID].asUUID(); +    } + +    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) +        { +            LLSettingsBase::TrackPosition keyframe = LLSettingsBase::TrackPosition((*it)[SETTING_KEYKFRAME].asReal()); +            keyframe = llclamp(keyframe, 0.0f, 1.0f); +            LLSettingsBase::ptr_t setting; + +             +            if ((*it).has(SETTING_KEYNAME)) +            { +                std::string key_name = (*it)[SETTING_KEYNAME]; +                if (i == TRACK_WATER) +                { +                    setting = used[key_name]; +                    if (setting && setting->getSettingsType() != "water") +                    { +                        LL_WARNS("DAYCYCLE") << "Water track referencing " << setting->getSettingsType() << " frame at " << keyframe << "." << LL_ENDL; +                        setting.reset(); +                    } +                } +                else +                { +                    setting = used[key_name]; +                    if (setting && setting->getSettingsType() != "sky") +                    { +                        LL_WARNS("DAYCYCLE") << "Sky track #" << i << " referencing " << setting->getSettingsType() << " frame at " << keyframe << "." << LL_ENDL; +                        setting.reset(); +                    } +                } +            } + +            if (setting) +            { +                if (i == TRACK_WATER) +                    haswater |= true; +                else +                    hassky |= true; + +                if (validate_frames && mDayTracks[i].size() > 0) +                { +                    // check if we hit close to anything in the list +                    LLSettingsDay::CycleTrack_t::value_type frame = getSettingsNearKeyframe(keyframe, i, DEFAULT_FRAME_SLOP_FACTOR); +                    if (frame.second) +                    { +                        // figure out direction of search +                        LLSettingsBase::TrackPosition found = frame.first; +                        LLSettingsBase::TrackPosition new_frame = keyframe; +                        F32 total_frame_shift = 0; +                        // We consider frame DEFAULT_FRAME_SLOP_FACTOR away as still encroaching, so add minimum increment +                        F32 move_factor = DEFAULT_FRAME_SLOP_FACTOR + DEFAULT_MULTISLIDER_INCREMENT; +                        bool move_forward = true; +                        if ((new_frame < found && (found - new_frame) <= DEFAULT_FRAME_SLOP_FACTOR) +                            || (new_frame > found && (new_frame - found) > DEFAULT_FRAME_SLOP_FACTOR)) +                        { +                            move_forward = false; +                        } + +                        if (move_forward) +                        { +                            CycleTrack_t::iterator iter = mDayTracks[i].find(found); +                            new_frame = found; // for total_frame_shift +                            while (total_frame_shift < 1) +                            { +                                // calculate shifted position from previous found point +                                total_frame_shift += move_factor + (found >= new_frame ? found : found + 1) - new_frame; +                                new_frame = found + move_factor; +                                if (new_frame > 1) new_frame--; + +                                // we know that current point is too close, go for next one +                                iter++; +                                if (iter == mDayTracks[i].end()) +                                { +                                    iter = mDayTracks[i].begin(); +                                } + +                                if (((iter->first >= (new_frame - DEFAULT_MULTISLIDER_INCREMENT)) && ((new_frame + DEFAULT_FRAME_SLOP_FACTOR) >= iter->first)) +                                    || ((iter->first < new_frame) && ((new_frame + DEFAULT_FRAME_SLOP_FACTOR) >= (iter->first + 1)))) +                                { +                                    // we are encroaching at new point as well +                                    found = iter->first; +                                } +                                else // (new_frame + DEFAULT_FRAME_SLOP_FACTOR < iter->first) +                                { +                                    //we found clear spot +                                    break; +                                } +                            } +                        } +                        else +                        { +                            CycleTrack_t::reverse_iterator iter = mDayTracks[i].rbegin(); +                            while (iter->first != found) +                            { +                                iter++; +                            } +                            new_frame = found; // for total_frame_shift +                            while (total_frame_shift < 1) +                            { +                                // calculate shifted position from current found point +                                total_frame_shift += move_factor + new_frame - (found <= new_frame ? found : found - 1); +                                new_frame = found - move_factor; +                                if (new_frame < 0) new_frame++; + +                                // we know that current point is too close, go for next one +                                iter++; +                                if (iter == mDayTracks[i].rend()) +                                { +                                    iter = mDayTracks[i].rbegin(); +                                } + +                                if ((iter->first <= (new_frame + DEFAULT_MULTISLIDER_INCREMENT) && (new_frame - DEFAULT_FRAME_SLOP_FACTOR) <= iter->first) +                                    || ((iter->first > new_frame) && ((new_frame - DEFAULT_FRAME_SLOP_FACTOR) <= (iter->first - 1)))) +                                { +                                    // we are encroaching at new point as well +                                    found = iter->first; +                                } +                                else // (new_frame - DEFAULT_FRAME_SLOP_FACTOR > iter->first) +                                { +                                    //we found clear spot +                                    break; +                                } +                            } + + +                        } + +                        if (total_frame_shift >= 1) +                        { +                            LL_WARNS("SETTINGS") << "Could not fix frame position, adding as is to position: " << keyframe << LL_ENDL; +                        } +                        else +                        { +                            // Mark as new position +                            keyframe = new_frame; +                        } +                    } +                } +                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); + +    if (!assetid.isNull()) +    { +        mSettings[SETTING_ASSETID] = assetid; +    } + +    mInitialized = true; +    return true; +} + + +//========================================================================= +LLSD LLSettingsDay::defaults() +{ +    static LLSD dfltsetting; + +    if (dfltsetting.size() == 0) +    { +        dfltsetting[SETTING_NAME] = DEFAULT_SETTINGS_NAME; +        dfltsetting[SETTING_TYPE] = "daycycle"; + +        LLSD frames(LLSD::emptyMap()); +        LLSD waterTrack; +        LLSD skyTrack; + +     +        const U32 FRAME_COUNT = 8; +        const F32 FRAME_STEP  = 1.0f / F32(FRAME_COUNT); +        F32 time = 0.0f; +        for (U32 i = 0; i < FRAME_COUNT; i++) +        { +            std::string name(DEFAULT_SETTINGS_NAME); +            name += ('a' + i); + +            std::string water_frame_name("water:"); +            std::string sky_frame_name("sky:"); + +            water_frame_name += name; +            sky_frame_name   += name; + +            waterTrack[SETTING_KEYKFRAME] = time; +            waterTrack[SETTING_KEYNAME]   = water_frame_name; + +            skyTrack[SETTING_KEYKFRAME] = time; +            skyTrack[SETTING_KEYNAME]   = sky_frame_name; + +            frames[water_frame_name] = LLSettingsWater::defaults(time); +            frames[sky_frame_name]   = LLSettingsSky::defaults(time); + +            time += FRAME_STEP; +        } + +        LLSD tracks; +        tracks.append(LLSDArray(waterTrack)); +        tracks.append(LLSDArray(skyTrack)); + +        dfltsetting[SETTING_TRACKS] = tracks; +        dfltsetting[SETTING_FRAMES] = frames; +    } + +    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; +                } + +                LLSettingsBase::TrackPosition 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]; +} + +const LLSettingsDay::CycleTrack_t& LLSettingsDay::getCycleTrackConst(S32 track) const +{ +    static CycleTrack_t emptyTrack; +    if (mDayTracks.size() <= track) +        return emptyTrack; + +    return mDayTracks[track]; +} + +bool LLSettingsDay::clearCycleTrack(S32 track) +{ +    if ((track < 0) || (track >= TRACK_MAX)) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to clear track (#" << track << ") out of range!" << LL_ENDL; +        return false; +    } +    mDayTracks[track].clear(); +    clearAssetId(); +    setDirtyFlag(true); +    return true; +} + +bool LLSettingsDay::replaceCycleTrack(S32 track, const CycleTrack_t &source) +{ +    if (source.empty()) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to copy an empty track." << LL_ENDL; +        return false; +    } + +    { +        LLSettingsBase::ptr_t   first((*source.begin()).second); +        std::string setting_type = first->getSettingsType(); + +        if (((setting_type == "water") && (track != 0)) || +            ((setting_type == "sky") && (track == 0))) +        { +            LL_WARNS("DAYCYCLE") << "Attempt to copy track missmatch" << LL_ENDL; +            return false; +        } +    } + +    if (!clearCycleTrack(track)) +        return false; + +    mDayTracks[track] = source; +    return true; +} + + +bool LLSettingsDay::isTrackEmpty(S32 track) const +{ +    if ((track < 0) || (track >= TRACK_MAX)) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to test track (#" << track << ") out of range!" << LL_ENDL; +        return true; +    } + +    return mDayTracks[track].empty(); +} + +//========================================================================= +void LLSettingsDay::startDayCycle() +{ +    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 (CycleTrack_t::iterator it = track.begin(); it != track.end(); ++it) +    { +        keyframes.push_back((*it).first); +    } + +    return keyframes; +} + +bool LLSettingsDay::moveTrackKeyframe(S32 trackno, const LLSettingsBase::TrackPosition& old_frame, const LLSettingsBase::TrackPosition& new_frame) +{ +    if ((trackno < 0) || (trackno >= TRACK_MAX)) +    { +        LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL; +        return false; +    } + +    if (llabs(old_frame - new_frame) < F_APPROXIMATELY_ZERO) +    { +        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; +        track[new_frame] = base; +        return true; +    } + +    return false; + +} + +bool LLSettingsDay::removeTrackKeyframe(S32 trackno, const LLSettingsBase::TrackPosition& 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, const LLSettingsBase::TrackPosition& keyframe) +{ +    setSettingsAtKeyframe(water, keyframe, TRACK_WATER); +} + +LLSettingsWater::ptr_t LLSettingsDay::getWaterAtKeyframe(const LLSettingsBase::TrackPosition& keyframe) const +{ +    LLSettingsBase* p = getSettingsAtKeyframe(keyframe, TRACK_WATER).get(); +    return LLSettingsWater::ptr_t((LLSettingsWater*)p); +} + +void LLSettingsDay::setSkyAtKeyframe(const LLSettingsSky::ptr_t &sky, const LLSettingsBase::TrackPosition& 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(const LLSettingsBase::TrackPosition& 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 PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(getSettingsAtKeyframe(keyframe, track)); +} + +void LLSettingsDay::setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, const LLSettingsBase::TrackPosition& keyframe, S32 track) +{ +    if ((track < 0) || (track >= TRACK_MAX)) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to set track (#" << track << ") out of range!" << LL_ENDL; +        return; +    } + +    std::string type = settings->getSettingsType(); +    if ((track == TRACK_WATER) && (type != "water")) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to add frame of type '" << type << "' to water track!" << LL_ENDL; +        llassert(type == "water"); +        return; +    } +    else if ((track != TRACK_WATER) && (type != "sky")) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to add frame of type '" << type << "' to sky track!" << LL_ENDL; +        llassert(type == "sky"); +        return; +    } + +    mDayTracks[track][llclamp(keyframe, 0.0f, 1.0f)] = settings; +    setDirtyFlag(true); +} + +LLSettingsBase::ptr_t LLSettingsDay::getSettingsAtKeyframe(const LLSettingsBase::TrackPosition& 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(); +} + +LLSettingsDay::CycleTrack_t::value_type LLSettingsDay::getSettingsNearKeyframe(const LLSettingsBase::TrackPosition &keyframe, S32 track, F32 fudge) const +{ +    if ((track < 0) || (track >= TRACK_MAX)) +    { +        LL_WARNS("DAYCYCLE") << "Attempt to get track (#" << track << ") out of range!" << LL_ENDL; +        return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); +    } + +    if (mDayTracks[track].empty()) +    { +        LL_INFOS("DAYCYCLE") << "Empty track" << LL_ENDL; +        return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); +    } + +    TrackPosition startframe(keyframe - fudge); +    if (startframe < 0.0f) +        startframe = 1.0f + startframe; + +    LLSettingsDay::CycleTrack_t collection = const_cast<CycleTrack_t &>(mDayTracks[track]); +    CycleTrack_t::iterator it = get_wrapping_atafter(collection, startframe); + +    F32 dist = get_wrapping_distance(startframe, (*it).first); + +    CycleTrack_t::iterator next_it = std::next(it); +    if ((dist <= DEFAULT_MULTISLIDER_INCREMENT) && next_it != collection.end()) +        return (*next_it); +    else if (dist <= (fudge * 2.0f)) +        return (*it); + +    return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); +} + +LLSettingsBase::TrackPosition LLSettingsDay::getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe) +{ +    return get_wrapping_atafter(mDayTracks[track], keyframe)->first; +} + +LLSettingsBase::TrackPosition LLSettingsDay::getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe) +{ +    return get_wrapping_atbefore(mDayTracks[track], keyframe)->first; +} + +LLSettingsDay::TrackBound_t LLSettingsDay::getBoundingEntries(LLSettingsDay::CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe) +{ +    return TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe)); +} + +LLUUID LLSettingsDay::GetDefaultAssetId() +{ +    return DEFAULT_ASSET_ID; +} + +//========================================================================= diff --git a/indra/llinventory/llsettingsdaycycle.h b/indra/llinventory/llsettingsdaycycle.h new file mode 100644 index 0000000000..f7f5bb63b6 --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.h @@ -0,0 +1,154 @@ +/** +* @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 PTR_NAMESPACE::shared_ptr<LLSettingsWater> LLSettingsWaterPtr_t; +typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> LLSettingsSkyPtr_t; + +class LLSettingsDay : public LLSettingsBase +{ +public: +    // 32-bit as LLSD only supports that width at present +    typedef S32Seconds Seconds; + +    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 Seconds MINIMUM_DAYLENGTH; +    static const Seconds DEFAULT_DAYLENGTH; +    static const Seconds MAXIMUM_DAYLENGTH; + +    static const Seconds MINIMUM_DAYOFFSET; +    static const Seconds DEFAULT_DAYOFFSET; +    static const Seconds MAXIMUM_DAYOFFSET; + +    static const S32     TRACK_WATER; +    static const S32     TRACK_GROUND_LEVEL; +    static const S32     TRACK_MAX; +    static const S32     FRAME_MAX; + +    static const F32     DEFAULT_FRAME_SLOP_FACTOR; + +    static const LLUUID DEFAULT_ASSET_ID; + +    typedef std::map<LLSettingsBase::TrackPosition, LLSettingsBase::ptr_t>  CycleTrack_t; +    typedef std::vector<CycleTrack_t>                                       CycleList_t; +    typedef PTR_NAMESPACE::shared_ptr<LLSettingsDay>                        ptr_t; +    typedef PTR_NAMESPACE::weak_ptr<LLSettingsDay>                          wptr_t; +    typedef std::vector<LLSettingsBase::TrackPosition>                      KeyframeList_t; +    typedef std::pair<CycleTrack_t::iterator, CycleTrack_t::iterator>       TrackBound_t; + +    //--------------------------------------------------------------------- +    LLSettingsDay(const LLSD &data); +    virtual ~LLSettingsDay() { }; + +    bool                        initialize(bool validate_frames = false); + +    virtual ptr_t               buildClone() const = 0; +    virtual ptr_t               buildDeepCloneAndUncompress() const = 0; +    virtual LLSD                getSettings() const SETTINGS_OVERRIDE; +    virtual LLSettingsType::type_e  getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_DAYCYCLE; } + + +    //--------------------------------------------------------------------- +    virtual std::string         getSettingsType() const SETTINGS_OVERRIDE { return std::string("daycycle"); } + +    // Settings status  +    virtual void                blend(const LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE; + +    static LLSD                 defaults(); + +    //--------------------------------------------------------------------- +    KeyframeList_t              getTrackKeyframes(S32 track); +    bool                        moveTrackKeyframe(S32 track, const LLSettingsBase::TrackPosition& old_frame, const LLSettingsBase::TrackPosition& new_frame); +    bool                        removeTrackKeyframe(S32 track, const LLSettingsBase::TrackPosition& frame); + +    void                        setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, const LLSettingsBase::TrackPosition& keyframe); +    LLSettingsWaterPtr_t        getWaterAtKeyframe(const LLSettingsBase::TrackPosition& keyframe) const; +    void                        setSkyAtKeyframe(const LLSettingsSkyPtr_t &sky, const LLSettingsBase::TrackPosition& keyframe, S32 track); +    LLSettingsSkyPtr_t          getSkyAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const; +    void                        setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, const LLSettingsBase::TrackPosition& keyframe, S32 track); +    LLSettingsBase::ptr_t       getSettingsAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const; +    CycleTrack_t::value_type    getSettingsNearKeyframe(const LLSettingsBase::TrackPosition &keyframe, S32 track, F32 fudge) 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; + +    void                        setInitialized(bool value = true) { mInitialized = value; } +    CycleTrack_t &              getCycleTrack(S32 track); +    const CycleTrack_t &        getCycleTrackConst(S32 track) const; +    bool                        clearCycleTrack(S32 track); +    bool                        replaceCycleTrack(S32 track, const CycleTrack_t &source); +    bool                        isTrackEmpty(S32 track) const; + +    virtual validation_list_t   getValidationList() const SETTINGS_OVERRIDE; +    static validation_list_t    validationList(); + +    virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } +	 +    LLSettingsBase::TrackPosition getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe); +    LLSettingsBase::TrackPosition getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe); + +    static LLUUID GetDefaultAssetId(); + +protected: +    LLSettingsDay(); + +    virtual void                updateSettings() SETTINGS_OVERRIDE; + +    bool                        mInitialized; + +private: +    CycleList_t                 mDayTracks; + +    LLSettingsBase::Seconds     mLastUpdateTime; + +    static CycleTrack_t::iterator   getEntryAtOrBefore(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); +    static CycleTrack_t::iterator   getEntryAtOrAfter(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); +    TrackBound_t                    getBoundingEntries(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); +}; + +#endif diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp new file mode 100644 index 0000000000..306c732920 --- /dev/null +++ b/indra/llinventory/llsettingssky.cpp @@ -0,0 +1,1757 @@ +/** +* @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 LLUUID IMG_BLOOM1("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); +    const LLUUID IMG_RAINBOW("11b4c57c-56b3-04ed-1f82-2004363882e4"); +    const LLUUID IMG_HALO("12149143-f599-91a7-77ac-b52a3c0f59cd"); +} + +namespace { +    LLQuaternion convert_azimuth_and_altitude_to_quat(F32 azimuth, F32 altitude) +    { +        F32 sinTheta = sin(azimuth); +        F32 cosTheta = cos(azimuth); +        F32 sinPhi   = sin(altitude); +        F32 cosPhi   = cos(altitude); + +        LLVector3 dir; +        // +x right, +z up, +y at...	 +        dir.mV[0] = cosTheta * cosPhi; +        dir.mV[1] = sinTheta * cosPhi;	 +        dir.mV[2] = sinPhi; + +        LLVector3 axis = LLVector3::x_axis % dir; +        axis.normalize(); + +        F32 angle = acos(LLVector3::x_axis * dir); + +        LLQuaternion quat; +        quat.setAngleAxis(angle, axis); + +        return quat; +    } +} + +static LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_SKYVALUES("Recalculate Sky"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_BODIES("Recalculate Heavenly Bodies"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_LIGHTING("Recalculate Lighting"); + +//========================================================================= +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_RAINBOW_TEXTUREID("rainbow_id"); +const std::string LLSettingsSky::SETTING_HALO_TEXTUREID("halo_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_CLOUD_VARIANCE("cloud_variance"); + +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_SCALE("moon_scale"); +const std::string LLSettingsSky::SETTING_MOON_TEXTUREID("moon_id"); +const std::string LLSettingsSky::SETTING_MOON_BRIGHTNESS("moon_brightness"); + +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_SCALE("sun_scale"); +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 std::string LLSettingsSky::SETTING_SKY_MOISTURE_LEVEL("moisture_level"); +const std::string LLSettingsSky::SETTING_SKY_DROPLET_RADIUS("droplet_radius"); +const std::string LLSettingsSky::SETTING_SKY_ICE_LEVEL("ice_level"); + +const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad"); + +static const LLUUID DEFAULT_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver +static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver +static const LLUUID DEFAULT_CLOUD_ID("1dc1368f-e8fe-f02d-a08d-9d9f11c1af6b"); + +const std::string LLSettingsSky::SETTING_LEGACY_HAZE("legacy_haze"); + +const F32 LLSettingsSky::DOME_OFFSET(0.96f); +const F32 LLSettingsSky::DOME_RADIUS(15000.f); + +namespace +{ + +LLSettingsSky::validation_list_t legacyHazeValidationList() +{ +    static LLSettingsBase::validation_list_t legacyHazeValidation; +    if (legacyHazeValidation.empty()) +    { +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_AMBIENT,             false,  LLSD::TypeArray,  +            boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), +                LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_DENSITY,        false,  LLSD::TypeArray,  +            boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), +                LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_HORIZON,        false,  LLSD::TypeArray,  +            boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), +                LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_DENSITY,        false,  LLSD::TypeReal,   +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_HORIZON,        false,  LLSD::TypeReal,   +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER,  false,  LLSD::TypeReal,   +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(2.0f))))); +        legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DISTANCE_MULTIPLIER, false,  LLSD::TypeReal, +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(1000.0f))))); +    } +    return legacyHazeValidation; +} + +LLSettingsSky::validation_list_t rayleighValidationList() +{ +    static LLSettingsBase::validation_list_t rayleighValidation; +    if (rayleighValidation.empty()) +    { +        rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH,      false,  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,   false,  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, false,  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, false,  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, false,  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,      false,  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,   false,  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, false,  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, false,  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, false,  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,      false,  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,   false,  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, false,  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, false,  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, false,  LLSD::TypeReal,   +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + +        mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, false,  LLSD::TypeReal,   +            boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); +    } +    return mieValidation; +} + +bool validateLegacyHaze(LLSD &value) +{ +    LLSettingsSky::validation_list_t legacyHazeValidations = legacyHazeValidationList(); +    llassert(value.type() == LLSD::TypeMap); +    LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations); +    if (result["errors"].size() > 0) +    { +        LL_WARNS("SETTINGS") << "Legacy Haze Config Validation errors: " << result["errors"] << LL_ENDL; +        return false; +    } +    if (result["warnings"].size() > 0) +    { +        LL_WARNS("SETTINGS") << "Legacy Haze Config Validation warnings: " << result["warnings"] << LL_ENDL; +        return false; +    } +    return true; +} + +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::TypeMap) +            { +                if (!validateRayleighLayers(layerConfig)) +                { +                    allGood = false; +                } +            } +            else if (layerConfig.type() == LLSD::TypeArray) +            { +                return validateRayleighLayers(layerConfig); +            } +            else +            { +                return LLSettingsBase::settingValidation(value, rayleighValidations); +            } +        } +        return allGood; +    }     +    llassert(value.type() == LLSD::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::TypeMap) +            { +                if (!validateAbsorptionLayers(layerConfig)) +                { +                    allGood = false; +                } +            } +            else if (layerConfig.type() == LLSD::TypeArray) +            { +                return validateAbsorptionLayers(layerConfig); +            } +            else +            { +                return LLSettingsBase::settingValidation(value, absorptionValidations); +            } +        } +        return allGood; +    } +    llassert(value.type() == LLSD::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::TypeMap) +            { +                if (!validateMieLayers(layerConfig)) +                { +                    allGood = false; +                } +            } +            else if (layerConfig.type() == LLSD::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["warnings"] << LL_ENDL; +        return false; +    } +    return true; +} + +} + +//========================================================================= +LLSettingsSky::LLSettingsSky(const LLSD &data) : +    LLSettingsBase(data), +    mNextSunTextureId(), +    mNextMoonTextureId(), +    mNextCloudTextureId(), +    mNextBloomTextureId(), +    mNextRainbowTextureId(), +    mNextHaloTextureId() +{ +} + +LLSettingsSky::LLSettingsSky(): +    LLSettingsBase(), +    mNextSunTextureId(), +    mNextMoonTextureId(), +    mNextCloudTextureId(), +    mNextBloomTextureId(), +    mNextRainbowTextureId(), +    mNextHaloTextureId() +{ +} + +void LLSettingsSky::replaceSettings(LLSD settings) +{ +    LLSettingsBase::replaceSettings(settings); +    mNextSunTextureId.setNull(); +    mNextMoonTextureId.setNull(); +    mNextCloudTextureId.setNull(); +    mNextBloomTextureId.setNull(); +    mNextRainbowTextureId.setNull(); +    mNextHaloTextureId.setNull(); +} + +void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother) +{ +    replaceWith(pother); + +    mNextSunTextureId = pother->mNextSunTextureId; +    mNextMoonTextureId = pother->mNextMoonTextureId; +    mNextCloudTextureId = pother->mNextCloudTextureId; +    mNextBloomTextureId = pother->mNextBloomTextureId; +    mNextRainbowTextureId = pother->mNextRainbowTextureId; +    mNextHaloTextureId = pother->mNextHaloTextureId; +} + +void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf)  +{ +    llassert(getSettingsType() == end->getSettingsType()); + +    LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end); +    if (other) +    { +        if (other->mSettings.has(SETTING_LEGACY_HAZE)) +        { +            if (!mSettings.has(SETTING_LEGACY_HAZE) || !mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT)) +            { +                // Special case since SETTING_AMBIENT is both in outer and legacy maps, we prioritize legacy one +                // see getAmbientColor(), we are about to replaceSettings(), so we are free to set it +                setAmbientColor(getAmbientColor()); +            } +        } +        else +        { +            if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT)) +            { +                // Special case due to ambient's duality +                // We need to match 'other's' structure for interpolation. +                // We are free to change mSettings, since we are about to reset it +                mSettings[SETTING_AMBIENT] = getAmbientColor().getValue(); +                mSettings[SETTING_LEGACY_HAZE].erase(SETTING_AMBIENT); +            } +        } + +        LLUUID cloud_noise_id = getCloudNoiseTextureId(); +        LLUUID cloud_noise_id_next = other->getCloudNoiseTextureId(); +        F64 cloud_shadow = 0; +        if (!cloud_noise_id.isNull() && cloud_noise_id_next.isNull()) +        { +            // If there is no cloud texture in destination, reduce coverage to imitate disappearance +            // See LLDrawPoolWLSky::renderSkyClouds... we don't blend present texture with null +            // Note: Probably can be done by shader +            cloud_shadow = lerp(mSettings[SETTING_CLOUD_SHADOW].asReal(), (F64)0.f, blendf); +            cloud_noise_id_next = cloud_noise_id; +        } +        else if (cloud_noise_id.isNull() && !cloud_noise_id_next.isNull()) +        { +            // Source has no cloud texture, reduce initial coverage to imitate appearance +            // use same texture as destination +            cloud_shadow = lerp((F64)0.f, other->mSettings[SETTING_CLOUD_SHADOW].asReal(), blendf); +            setCloudNoiseTextureId(cloud_noise_id_next); +        } +        else +        { +            cloud_shadow = lerp(mSettings[SETTING_CLOUD_SHADOW].asReal(), other->mSettings[SETTING_CLOUD_SHADOW].asReal(), blendf); +        } + +        LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf); +        blenddata[SETTING_CLOUD_SHADOW] = LLSD::Real(cloud_shadow); +        replaceSettings(blenddata); +        mNextSunTextureId = other->getSunTextureId(); +        mNextMoonTextureId = other->getMoonTextureId(); +        mNextCloudTextureId = cloud_noise_id_next; +        mNextBloomTextureId = other->getBloomTextureId(); +        mNextRainbowTextureId = other->getRainbowTextureId(); +        mNextHaloTextureId = other->getHaloTextureId(); +    } +    else +    { +        LL_WARNS("SETTINGS") << "Could not cast end settings to sky. No blend performed." << LL_ENDL; +    } + +    setBlendFactor(blendf); +} + +LLSettingsSky::stringset_t LLSettingsSky::getSkipInterpolateKeys() const +{ +    static stringset_t skipSet; + +    if (skipSet.empty()) +    { +        skipSet = LLSettingsBase::getSkipInterpolateKeys(); +        skipSet.insert(SETTING_RAYLEIGH_CONFIG); +        skipSet.insert(SETTING_MIE_CONFIG); +        skipSet.insert(SETTING_ABSORPTION_CONFIG); +        skipSet.insert(SETTING_CLOUD_SHADOW); +    } + +    return skipSet; +} + +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]]]]]]]]]] +        validation.push_back(Validator(SETTING_BLOOM_TEXTUREID,     true,  LLSD::TypeUUID)); +        validation.push_back(Validator(SETTING_RAINBOW_TEXTUREID,   false,  LLSD::TypeUUID)); +        validation.push_back(Validator(SETTING_HALO_TEXTUREID,      false,  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.0f)(1.0f)(3.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.0f)(1.0f)(1.0f)("*"))))); +        validation.push_back(Validator(SETTING_CLOUD_SCALE,         true,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(3.0f))))); +        validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE,   true,  LLSD::TypeArray,  +            boost::bind(&Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(-50.0f)(-50.0f)), +                LLSD(LLSDArray(50.0f)(50.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_CLOUD_VARIANCE,      false,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + +        validation.push_back(Validator(SETTING_DOME_OFFSET,         false, LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); +        validation.push_back(Validator(SETTING_DOME_RADIUS,         false, LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f))))); +        validation.push_back(Validator(SETTING_GAMMA,               true,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f))))); +        validation.push_back(Validator(SETTING_GLOW,                true,  LLSD::TypeArray,  +            boost::bind(&Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(0.2f)("*")(-10.0f)("*")), +                LLSD(LLSDArray(40.0f)("*")(10.0f)("*"))))); +         +        validation.push_back(Validator(SETTING_MAX_Y,               true,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10000.0f))))); +        validation.push_back(Validator(SETTING_MOON_ROTATION,       true,  LLSD::TypeArray, &Validator::verifyQuaternionNormal)); +        validation.push_back(Validator(SETTING_MOON_SCALE,          false, LLSD::TypeReal, +                boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); +        validation.push_back(Validator(SETTING_MOON_TEXTUREID,      false, LLSD::TypeUUID)); +        validation.push_back(Validator(SETTING_MOON_BRIGHTNESS,     false,  LLSD::TypeReal,  +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + +        validation.push_back(Validator(SETTING_STAR_BRIGHTNESS,     true,  LLSD::TypeReal,  +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(500.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_SCALE,           false, LLSD::TypeReal, +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); +        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_SKY_MOISTURE_LEVEL,      false,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + +        validation.push_back(Validator(SETTING_SKY_DROPLET_RADIUS,      false,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(5.0f)(1000.0f))))); + +        validation.push_back(Validator(SETTING_SKY_ICE_LEVEL,      false,  LLSD::TypeReal,   +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + +        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)); +        validation.push_back(Validator(SETTING_LEGACY_HAZE, false, LLSD::TypeMap, &validateLegacyHaze)); +    } +    return validation; +} + +LLSD LLSettingsSky::createDensityProfileLayer( +    F32 width, +    F32 exponential_term, +    F32 exponential_scale_factor, +    F32 linear_term, +    F32 constant_term, +    F32 aniso_factor) +{ +    LLSD dflt_layer; +    dflt_layer[SETTING_DENSITY_PROFILE_WIDTH]            = width; // 0 -> the entire atmosphere +    dflt_layer[SETTING_DENSITY_PROFILE_EXP_TERM]         = exponential_term; +    dflt_layer[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = exponential_scale_factor; +    dflt_layer[SETTING_DENSITY_PROFILE_LINEAR_TERM]      = linear_term; +    dflt_layer[SETTING_DENSITY_PROFILE_CONSTANT_TERM]    = constant_term; + +    if (aniso_factor != 0.0f) +    { +        dflt_layer[SETTING_MIE_ANISOTROPY_FACTOR] = aniso_factor; +    } + +    return dflt_layer; +} + +LLSD LLSettingsSky::createSingleLayerDensityProfile( +    F32 width, +    F32 exponential_term, +    F32 exponential_scale_factor, +    F32 linear_term, +    F32 constant_term, +    F32 aniso_factor) +{ +    LLSD dflt; +    LLSD dflt_layer = createDensityProfileLayer(width, exponential_term, exponential_scale_factor, linear_term, constant_term, aniso_factor); +    dflt.append(dflt_layer); +    return dflt; +} + +LLSD LLSettingsSky::rayleighConfigDefault() +{ +    return createSingleLayerDensityProfile(0.0f,  1.0f, -1.0f / 8000.0f, 0.0f, 0.0f); +} + +LLSD LLSettingsSky::absorptionConfigDefault() +{ +// absorption (ozone) has two linear ramping zones +    LLSD dflt_absorption_layer_a = createDensityProfileLayer(25000.0f, 0.0f, 0.0f, -1.0f / 25000.0f, -2.0f / 3.0f); +    LLSD dflt_absorption_layer_b = createDensityProfileLayer(0.0f, 0.0f, 0.0f, -1.0f / 15000.0f, 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 = createSingleLayerDensityProfile(0.0f,  1.0f, -1.0f / 1200.0f, 0.0f, 0.0f, 0.8f); +    return dflt_mie; +} + +LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position) +{ +    static LLSD dfltsetting; + +    if (dfltsetting.size() == 0) +    { +        LLQuaternion sunquat; +        LLQuaternion moonquat; + +        F32 azimuth  = (F_PI * position) + (80.0f * DEG_TO_RAD); +        F32 altitude = (F_PI * position); + +        // give the sun and moon slightly different tracks through the sky +        // instead of positioning them at opposite poles from each other... +        sunquat  = convert_azimuth_and_altitude_to_quat(altitude,                   azimuth); +        moonquat = convert_azimuth_and_altitude_to_quat(altitude + (F_PI * 0.125f), azimuth + (F_PI * 0.125f)); + +        // Magic constants copied form dfltsetting.xml  +        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(0.0f)(0.0f); +        dfltsetting[SETTING_CLOUD_SHADOW]       = LLSD::Real(0.2699); +        dfltsetting[SETTING_CLOUD_VARIANCE]     = LLSD::Real(0.0); + +        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_MAX_Y]              = LLSD::Real(1605); +        dfltsetting[SETTING_MOON_ROTATION]      = moonquat.getValue(); +        dfltsetting[SETTING_MOON_BRIGHTNESS]    = LLSD::Real(0.5f); + +        dfltsetting[SETTING_STAR_BRIGHTNESS]    = LLSD::Real(250.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]    = GetDefaultBloomTextureId(); +        dfltsetting[SETTING_CLOUD_TEXTUREID]    = GetDefaultCloudNoiseTextureId(); +        dfltsetting[SETTING_MOON_TEXTUREID]     = GetDefaultMoonTextureId(); +        dfltsetting[SETTING_SUN_TEXTUREID]      = GetDefaultSunTextureId(); +        dfltsetting[SETTING_RAINBOW_TEXTUREID]  = GetDefaultRainbowTextureId(); +        dfltsetting[SETTING_HALO_TEXTUREID]     = GetDefaultHaloTextureId(); + +        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.00045f; + +        dfltsetting[SETTING_SKY_MOISTURE_LEVEL] = 0.0f; +        dfltsetting[SETTING_SKY_DROPLET_RADIUS] = 800.0f; +        dfltsetting[SETTING_SKY_ICE_LEVEL]      = 0.0f; + +        dfltsetting[SETTING_RAYLEIGH_CONFIG]    = rayleighConfigDefault(); +        dfltsetting[SETTING_MIE_CONFIG]         = mieConfigDefault(); +        dfltsetting[SETTING_ABSORPTION_CONFIG]  = absorptionConfigDefault(); +    } + +    return dfltsetting; +} + +LLSD LLSettingsSky::translateLegacyHazeSettings(const LLSD& legacy) +{ +    LLSD legacyhazesettings; + +// AdvancedAtmospherics TODO +// These need to be translated into density profile info in the new settings format... +// LEGACY_ATMOSPHERICS     +    if (legacy.has(SETTING_AMBIENT)) +    { +        legacyhazesettings[SETTING_AMBIENT] = LLColor3(legacy[SETTING_AMBIENT]).getValue(); +    } +    if (legacy.has(SETTING_BLUE_DENSITY)) +    { +        legacyhazesettings[SETTING_BLUE_DENSITY] = LLColor3(legacy[SETTING_BLUE_DENSITY]).getValue(); +    } +    if (legacy.has(SETTING_BLUE_HORIZON)) +    { +        legacyhazesettings[SETTING_BLUE_HORIZON] = LLColor3(legacy[SETTING_BLUE_HORIZON]).getValue(); +    } +    if (legacy.has(SETTING_DENSITY_MULTIPLIER)) +    { +        legacyhazesettings[SETTING_DENSITY_MULTIPLIER] = LLSD::Real(legacy[SETTING_DENSITY_MULTIPLIER][0].asReal()); +    } +    if (legacy.has(SETTING_DISTANCE_MULTIPLIER)) +    { +        legacyhazesettings[SETTING_DISTANCE_MULTIPLIER] = LLSD::Real(legacy[SETTING_DISTANCE_MULTIPLIER][0].asReal()); +    } +    if (legacy.has(SETTING_HAZE_DENSITY)) +    { +        legacyhazesettings[SETTING_HAZE_DENSITY] = LLSD::Real(legacy[SETTING_HAZE_DENSITY][0].asReal()); +    } +    if (legacy.has(SETTING_HAZE_HORIZON)) +    { +        legacyhazesettings[SETTING_HAZE_HORIZON] = LLSD::Real(legacy[SETTING_HAZE_HORIZON][0].asReal()); +    } + +    return legacyhazesettings; +} + +LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy) +{ +    bool converted_something(false); +    LLSD newsettings(defaults()); + +    // Move legacy haze parameters to an inner map +    // allowing backward compat and simple conversion to legacy format +    LLSD legacyhazesettings; +    legacyhazesettings = translateLegacyHazeSettings(legacy); +    if (legacyhazesettings.size() > 0) +    { +        newsettings[SETTING_LEGACY_HAZE] = legacyhazesettings; +        converted_something |= true; +    } + +    if (legacy.has(SETTING_CLOUD_COLOR)) +    { +        newsettings[SETTING_CLOUD_COLOR] = LLColor3(legacy[SETTING_CLOUD_COLOR]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_CLOUD_POS_DENSITY1)) +    { +        newsettings[SETTING_CLOUD_POS_DENSITY1] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY1]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_CLOUD_POS_DENSITY2)) +    { +        newsettings[SETTING_CLOUD_POS_DENSITY2] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY2]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_CLOUD_SCALE)) +    { +        newsettings[SETTING_CLOUD_SCALE] = LLSD::Real(legacy[SETTING_CLOUD_SCALE][0].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_CLOUD_SCROLL_RATE)) +    { +        LLVector2 cloud_scroll(legacy[SETTING_CLOUD_SCROLL_RATE]); + +        cloud_scroll -= LLVector2(10, 10); +        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(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_CLOUD_SHADOW)) +    { +        newsettings[SETTING_CLOUD_SHADOW] = LLSD::Real(legacy[SETTING_CLOUD_SHADOW][0].asReal()); +        converted_something |= true; +    } +     + +    if (legacy.has(SETTING_GAMMA)) +    { +        newsettings[SETTING_GAMMA] = legacy[SETTING_GAMMA][0].asReal(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_GLOW)) +    { +        newsettings[SETTING_GLOW] = LLColor3(legacy[SETTING_GLOW]).getValue(); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_MAX_Y)) +    { +        newsettings[SETTING_MAX_Y] = LLSD::Real(legacy[SETTING_MAX_Y][0].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_STAR_BRIGHTNESS)) +    { +        newsettings[SETTING_STAR_BRIGHTNESS] = LLSD::Real(legacy[SETTING_STAR_BRIGHTNESS].asReal() * 250.0f); +        converted_something |= true; +    } +    if (legacy.has(SETTING_SUNLIGHT_COLOR)) +    { +        newsettings[SETTING_SUNLIGHT_COLOR] = LLColor4(legacy[SETTING_SUNLIGHT_COLOR]).getValue(); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_PLANET_RADIUS)) +    { +        newsettings[SETTING_PLANET_RADIUS] = LLSD::Real(legacy[SETTING_PLANET_RADIUS].asReal()); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_SKY_BOTTOM_RADIUS)) +    { +        newsettings[SETTING_SKY_BOTTOM_RADIUS] = LLSD::Real(legacy[SETTING_SKY_BOTTOM_RADIUS].asReal()); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_SKY_TOP_RADIUS)) +    { +        newsettings[SETTING_SKY_TOP_RADIUS] = LLSD::Real(legacy[SETTING_SKY_TOP_RADIUS].asReal()); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_SUN_ARC_RADIANS)) +    { +        newsettings[SETTING_SUN_ARC_RADIANS] = LLSD::Real(legacy[SETTING_SUN_ARC_RADIANS].asReal()); +        converted_something |= true; +    } + +    if (legacy.has(SETTING_LEGACY_EAST_ANGLE) && legacy.has(SETTING_LEGACY_SUN_ANGLE)) +    { +        // get counter-clockwise radian angle from clockwise legacy WL east angle... +        F32 azimuth  = -legacy[SETTING_LEGACY_EAST_ANGLE].asReal(); +        F32 altitude =  legacy[SETTING_LEGACY_SUN_ANGLE].asReal(); +         +        LLQuaternion sunquat  = convert_azimuth_and_altitude_to_quat(azimuth, altitude); +        // original WL moon dir was diametrically opposed to the sun dir +        LLQuaternion moonquat = convert_azimuth_and_altitude_to_quat(azimuth + F_PI, -altitude); + +        newsettings[SETTING_SUN_ROTATION]  = sunquat.getValue(); +        newsettings[SETTING_MOON_ROTATION] = moonquat.getValue(); +        converted_something |= true; +    } + +    if (!converted_something) +        return LLSD(); + +    return newsettings; +} + +void LLSettingsSky::updateSettings() +{ +    LL_RECORD_BLOCK_TIME(FTM_RECALCULATE_SKYVALUES); + +    // base class clears dirty flag so as to not trigger recursive update +    LLSettingsBase::updateSettings(); + +    // NOTE: these functions are designed to do nothing unless a dirty bit has been set +    // so if you add new settings that are referenced by these update functions, +    // you'll need to insure that your setter updates the dirty bits as well +    calculateHeavenlyBodyPositions(); +    calculateLightSettings(); +} + +F32 LLSettingsSky::getSunMoonGlowFactor() const +{ +    return getIsSunUp()  ? 1.0f  : +           getIsMoonUp() ? getMoonBrightness() * 0.25 : 0.0f; +} + +bool LLSettingsSky::getIsSunUp() const +{ +    LLVector3 sunDir = getSunDirection(); +    return sunDir.mV[2] >= 0.0f; +} + +bool LLSettingsSky::getIsMoonUp() const +{ +    LLVector3 moonDir = getMoonDirection(); +    return moonDir.mV[2] >= 0.0f; +} + +void LLSettingsSky::calculateHeavenlyBodyPositions()  const +{ +    LLQuaternion sunq  = getSunRotation(); +    LLQuaternion moonq = getMoonRotation(); + +    mSunDirection  = LLVector3::x_axis * sunq; +    mMoonDirection = LLVector3::x_axis * moonq; + +    mSunDirection.normalize(); +    mMoonDirection.normalize(); + +    if (mSunDirection.lengthSquared() < 0.01f) +        LL_WARNS("SETTINGS") << "Zero length sun direction. Wailing and gnashing of teeth may follow... or not." << LL_ENDL; +    if (mMoonDirection.lengthSquared() < 0.01f) +        LL_WARNS("SETTINGS") << "Zero length moon direction. Wailing and gnashing of teeth may follow... or not." << LL_ENDL; +} + +LLVector3 LLSettingsSky::getLightDirection() const +{ +    update(); + +    // is the normal from the sun or the moon +    if (getIsSunUp()) +    { +        return mSunDirection; +    } +    else if (getIsMoonUp()) +    { +        return mMoonDirection; +    } + +    return LLVector3::z_axis_neg; +} + +LLColor3 LLSettingsSky::getLightDiffuse() const +{ +    update(); + +    // is the normal from the sun or the moon +    if (getIsSunUp()) +    { +        return getSunDiffuse(); +    } +    else if (getIsMoonUp()) +    { +        return getMoonDiffuse(); +    } + +    return LLColor3::white; +} + +LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const +{ +    if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) +    { +        return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]); +    } +    if (mSettings.has(key)) +    { +        return LLColor3(mSettings[key]); +    } +    return default_value; +} + +F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const +{ +    if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) +    { +        return mSettings[SETTING_LEGACY_HAZE][key].asReal(); +    } +    if (mSettings.has(key)) +    { +        return mSettings[key].asReal(); +    } +    return default_value; +} + +LLColor3 LLSettingsSky::getAmbientColor() const +{ +    return getColor(SETTING_AMBIENT, LLColor3(0.25f, 0.25f, 0.25f)); +} + +LLColor3 LLSettingsSky::getAmbientColorClamped() const +{ +    LLColor3 ambient = getAmbientColor(); + +    F32 max_color = llmax(ambient.mV[0], ambient.mV[1], ambient.mV[2]); +    if (max_color > 1.0f) +    { +        ambient *= 1.0f/max_color; +    } + +    return ambient; +} + +LLColor3 LLSettingsSky::getBlueDensity() const +{ +    return getColor(SETTING_BLUE_DENSITY, LLColor3(0.2447f, 0.4487f, 0.7599f)); +} + +LLColor3 LLSettingsSky::getBlueHorizon() const +{ +    return getColor(SETTING_BLUE_HORIZON, LLColor3(0.4954f, 0.4954f, 0.6399f)); +} + +F32 LLSettingsSky::getHazeDensity() const +{ +    return getFloat(SETTING_HAZE_DENSITY, 0.7f); +} + +F32 LLSettingsSky::getHazeHorizon() const +{ +    return getFloat(SETTING_HAZE_HORIZON, 0.19f); +} + +F32 LLSettingsSky::getDensityMultiplier() const +{ +    return getFloat(SETTING_DENSITY_MULTIPLIER, 0.0001f); +} + +F32 LLSettingsSky::getDistanceMultiplier() const +{ +    return getFloat(SETTING_DISTANCE_MULTIPLIER, 0.8f); +} + +void LLSettingsSky::setPlanetRadius(F32 radius) +{ +    mSettings[SETTING_PLANET_RADIUS] = radius; +} + +void LLSettingsSky::setSkyBottomRadius(F32 radius) +{ +    mSettings[SETTING_SKY_BOTTOM_RADIUS] = radius; +} + +void LLSettingsSky::setSkyTopRadius(F32 radius) +{ +    mSettings[SETTING_SKY_TOP_RADIUS] = radius; +} + +void LLSettingsSky::setSunArcRadians(F32 radians) +{ +    mSettings[SETTING_SUN_ARC_RADIANS] = radians; +} + +void LLSettingsSky::setMieAnisotropy(F32 aniso_factor) +{ +    getMieConfig()[SETTING_MIE_ANISOTROPY_FACTOR] = aniso_factor; +} + +void LLSettingsSky::setSkyMoistureLevel(F32 moisture_level) +{ +    setValue(SETTING_SKY_MOISTURE_LEVEL, moisture_level); +} + +void LLSettingsSky::setSkyDropletRadius(F32 radius) +{ +    setValue(SETTING_SKY_DROPLET_RADIUS,radius); +} + +void LLSettingsSky::setSkyIceLevel(F32 ice_level) +{ +    setValue(SETTING_SKY_ICE_LEVEL, ice_level); +} + +void LLSettingsSky::setAmbientColor(const LLColor3 &val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT] = val.getValue(); +    setDirtyFlag(true); +} + +void LLSettingsSky::setBlueDensity(const LLColor3 &val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_DENSITY] = val.getValue(); +    setDirtyFlag(true); +} + +void LLSettingsSky::setBlueHorizon(const LLColor3 &val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_HORIZON] = val.getValue(); +    setDirtyFlag(true); +} + +void LLSettingsSky::setDensityMultiplier(F32 val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_DENSITY_MULTIPLIER] = val; +    setDirtyFlag(true); +} + +void LLSettingsSky::setDistanceMultiplier(F32 val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_DISTANCE_MULTIPLIER] = val; +    setDirtyFlag(true); +} + +void LLSettingsSky::setHazeDensity(F32 val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_DENSITY] = val; +    setDirtyFlag(true); +} + +void LLSettingsSky::setHazeHorizon(F32 val) +{ +    mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_HORIZON] = val; +    setDirtyFlag(true); +} + +// Get total from rayleigh and mie density values for normalization +LLColor3 LLSettingsSky::getTotalDensity() const +{ +    LLColor3    blue_density = getBlueDensity(); +    F32         haze_density = getHazeDensity(); +    LLColor3 total_density = blue_density + smear(haze_density); +    return total_density; +} + +// Sunlight attenuation effect (hue and brightness) due to atmosphere +// this is used later for sunlight modulation at various altitudes +LLColor3 LLSettingsSky::getLightAttenuation(F32 distance) const +{ +    F32         density_multiplier = getDensityMultiplier(); +    LLColor3    blue_density       = getBlueDensity(); +    F32         haze_density       = getHazeDensity(); +    // Approximate line integral over requested distance +    LLColor3    light_atten = (blue_density * 1.0 + smear(haze_density * 0.25f)) * density_multiplier * distance; +    return light_atten; +} + +LLColor3 LLSettingsSky::getLightTransmittance(F32 distance) const +{ +    LLColor3 total_density      = getTotalDensity(); +    F32      density_multiplier = getDensityMultiplier(); +    // Transparency (-> density) from Beer's law +    LLColor3 transmittance = componentExp(total_density * -(density_multiplier * distance)); +    return transmittance; +} + +// performs soft scale clip and gamma correction ala the shader implementation +// scales colors down to 0 - 1 range preserving relative ratios +LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const +{ +    F32 gamma = getGamma(); + +    LLColor3 v(in); +    // scale down to 0 to 1 range preserving relative ratio (aka homegenize) +    F32 max_color = llmax(llmax(in.mV[0], in.mV[1]), in.mV[2]); +    if (max_color > 1.0f) +    { +        v *= 1.0f / max_color; +    } + +    LLColor3 color = in * 2.0f; +	color = smear(1.f) - componentSaturate(color); // clamping after mul seems wrong, but prevents negative colors... +	componentPow(color, gamma); +	color = smear(1.f) - color; +    return color; +} + +LLVector3 LLSettingsSky::getSunDirection() const +{ +    update(); +    return mSunDirection; +} + +LLVector3 LLSettingsSky::getMoonDirection() const +{ +    update(); +    return mMoonDirection; +} + +LLColor4 LLSettingsSky::getMoonAmbient() const +{ +    update(); +    return mMoonAmbient; +} + +LLColor3 LLSettingsSky::getMoonDiffuse() const +{ +    update(); +    return mMoonDiffuse; +} + +LLColor4 LLSettingsSky::getSunAmbient() const +{ +    update(); +    return mSunAmbient; +} + +LLColor3 LLSettingsSky::getSunDiffuse() const +{ +    update(); +    return mSunDiffuse; +} + +LLColor4 LLSettingsSky::getHazeColor() const +{ +    update(); +    return mHazeColor; +} + +LLColor4 LLSettingsSky::getTotalAmbient() const +{ +    update(); +    return mTotalAmbient; +} + +LLColor3 LLSettingsSky::getMoonlightColor() const +{ +    return getSunlightColor(); //moon and sun share light color +} + +void LLSettingsSky::clampColor(LLColor3& color, F32 gamma, F32 scale) const +{ +    F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); +    if (max_color > scale) +    { +        color *= scale/max_color; +    } +    LLColor3 linear(color); +    linear *= 1.0 / scale; +    linear = smear(1.0f) - linear; +    linear = componentPow(linear, gamma); +    linear *= scale; +    color = linear; +} + +void LLSettingsSky::calculateLightSettings() const +{ +    // Initialize temp variables +    LLColor3    sunlight = getSunlightColor(); +    LLColor3    ambient  = getAmbientColor(); + +    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 +    F32         max_y               = getMaxY(); +    LLColor3    light_atten         = getLightAttenuation(max_y); +    LLColor3    light_transmittance = getLightTransmittance(max_y); + +    // and vary_sunlight will work properly with moon light +    const F32 LIMIT = FLT_EPSILON * 8.0f; + +    F32 lighty = fabs(lightnorm[2]); +    if(lighty >= LIMIT) +    { +        lighty = 1.f / lighty; +    } +    lighty = llmax(LIMIT, lighty); +    componentMultBy(sunlight, componentExp((light_atten * -1.f) * lighty)); +    componentMultBy(sunlight, light_transmittance); + +    //increase ambient when there are more clouds +    LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5; + +    //brightness of surface both sunlight and ambient +    mSunDiffuse = sunlight; +    mSunAmbient = tmpAmbient; + +    F32 haze_horizon = getHazeHorizon(); +     +    sunlight *= 1.0 - cloud_shadow; +    sunlight += tmpAmbient; + +    mHazeColor = getBlueHorizon() * getBlueDensity() * sunlight; +    mHazeColor += LLColor4(haze_horizon, haze_horizon, haze_horizon, haze_horizon) * getHazeDensity() * sunlight; + +    F32 moon_brightness = getIsMoonUp() ? getMoonBrightness() : 0.001f; + +    LLColor3 moonlight = getMoonlightColor(); +    LLColor3 moonlight_b(0.66, 0.66, 1.2); // scotopic ambient value + +    componentMultBy(moonlight, componentExp((light_atten * -1.f) * lighty)); + +    mMoonDiffuse  = componentMult(moonlight, light_transmittance) * moon_brightness; +    mMoonAmbient  = moonlight_b * 0.0125f; + +    mTotalAmbient = ambient; +} + +LLUUID LLSettingsSky::GetDefaultAssetId() +{ +    return DEFAULT_ASSET_ID; +} + +LLUUID LLSettingsSky::GetDefaultSunTextureId() +{ +    return LLUUID::null; +} + + +LLUUID LLSettingsSky::GetBlankSunTextureId() +{ +    return DEFAULT_SUN_ID; +} + +LLUUID LLSettingsSky::GetDefaultMoonTextureId() +{ +    return DEFAULT_MOON_ID; +} + +LLUUID LLSettingsSky::GetDefaultCloudNoiseTextureId() +{ +    return DEFAULT_CLOUD_ID; +} + +LLUUID LLSettingsSky::GetDefaultBloomTextureId() +{ +    return IMG_BLOOM1; +} + +LLUUID LLSettingsSky::GetDefaultRainbowTextureId() +{ +    return IMG_RAINBOW; +} + +LLUUID LLSettingsSky::GetDefaultHaloTextureId() +{ +    return IMG_HALO; +} + +F32 LLSettingsSky::getPlanetRadius() const +{ +    return mSettings[SETTING_PLANET_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyMoistureLevel() const +{ +    return mSettings[SETTING_SKY_MOISTURE_LEVEL].asReal(); +} + +F32 LLSettingsSky::getSkyDropletRadius() const +{ +    return mSettings[SETTING_SKY_DROPLET_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyIceLevel() const +{ +    return mSettings[SETTING_SKY_ICE_LEVEL].asReal(); +} + +F32 LLSettingsSky::getSkyBottomRadius() const +{ +    return mSettings[SETTING_SKY_BOTTOM_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyTopRadius() const +{ +    return mSettings[SETTING_SKY_TOP_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSunArcRadians() const +{ +    return mSettings[SETTING_SUN_ARC_RADIANS].asReal(); +} + +F32 LLSettingsSky::getMieAnisotropy() const +{ +    return getMieConfig()[SETTING_MIE_ANISOTROPY_FACTOR].asReal(); +} +  +LLSD LLSettingsSky::getRayleighConfig() const +{ +    LLSD copy = *(mSettings[SETTING_RAYLEIGH_CONFIG].beginArray()); +    return copy; +} + +LLSD LLSettingsSky::getMieConfig() const +{ +    LLSD copy = *(mSettings[SETTING_MIE_CONFIG].beginArray()); +    return copy; +} + +LLSD LLSettingsSky::getAbsorptionConfig() const +{ +    LLSD copy = *(mSettings[SETTING_ABSORPTION_CONFIG].beginArray()); +    return copy; +} +    +LLSD LLSettingsSky::getRayleighConfigs() const +{ +    return mSettings[SETTING_RAYLEIGH_CONFIG]; +} + +LLSD LLSettingsSky::getMieConfigs() const +{ +    return mSettings[SETTING_MIE_CONFIG]; +} + +LLSD LLSettingsSky::getAbsorptionConfigs() const +{ +    return mSettings[SETTING_ABSORPTION_CONFIG]; +} + +void LLSettingsSky::setRayleighConfigs(const LLSD& rayleighConfig) +{ +    mSettings[SETTING_RAYLEIGH_CONFIG] = rayleighConfig; +} + +void LLSettingsSky::setMieConfigs(const LLSD& mieConfig) +{ +    mSettings[SETTING_MIE_CONFIG] = mieConfig; +} + +void LLSettingsSky::setAbsorptionConfigs(const LLSD& absorptionConfig) +{ +    mSettings[SETTING_ABSORPTION_CONFIG] = absorptionConfig; +} + +LLUUID LLSettingsSky::getBloomTextureId() const +{ +    return mSettings[SETTING_BLOOM_TEXTUREID].asUUID(); +} + +LLUUID LLSettingsSky::getRainbowTextureId() const +{ +    return mSettings[SETTING_RAINBOW_TEXTUREID].asUUID(); +} + +LLUUID LLSettingsSky::getHaloTextureId() const +{ +    return mSettings[SETTING_HALO_TEXTUREID].asUUID(); +} + +//--------------------------------------------------------------------- +LLColor3 LLSettingsSky::getCloudColor() const +{ +    return LLColor3(mSettings[SETTING_CLOUD_COLOR]); +} + +void LLSettingsSky::setCloudColor(const LLColor3 &val) +{ +    setValue(SETTING_CLOUD_COLOR, val); +} + +LLUUID LLSettingsSky::getCloudNoiseTextureId() const +{ +    return mSettings[SETTING_CLOUD_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setCloudNoiseTextureId(const LLUUID &id) +{ +    setValue(SETTING_CLOUD_TEXTUREID, id); +} + +LLColor3 LLSettingsSky::getCloudPosDensity1() const +{ +    return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY1]); +} + +void LLSettingsSky::setCloudPosDensity1(const LLColor3 &val) +{ +    setValue(SETTING_CLOUD_POS_DENSITY1, val); +} + +LLColor3 LLSettingsSky::getCloudPosDensity2() const +{ +    return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY2]); +} + +void LLSettingsSky::setCloudPosDensity2(const LLColor3 &val) +{ +    setValue(SETTING_CLOUD_POS_DENSITY2, val); +} + +F32 LLSettingsSky::getCloudScale() const +{ +    return mSettings[SETTING_CLOUD_SCALE].asReal(); +} + +void LLSettingsSky::setCloudScale(F32 val) +{ +    setValue(SETTING_CLOUD_SCALE, val); +} + +LLVector2 LLSettingsSky::getCloudScrollRate() const +{ +    return LLVector2(mSettings[SETTING_CLOUD_SCROLL_RATE]); +} + +void LLSettingsSky::setCloudScrollRate(const LLVector2 &val) +{ +    setValue(SETTING_CLOUD_SCROLL_RATE, val); +} + +void LLSettingsSky::setCloudScrollRateX(F32 val) +{ +    mSettings[SETTING_CLOUD_SCROLL_RATE][0] = val; +    setDirtyFlag(true); +} + +void LLSettingsSky::setCloudScrollRateY(F32 val) +{ +    mSettings[SETTING_CLOUD_SCROLL_RATE][1] = val; +    setDirtyFlag(true); +} + +F32 LLSettingsSky::getCloudShadow() const +{ +    return mSettings[SETTING_CLOUD_SHADOW].asReal(); +} + +void LLSettingsSky::setCloudShadow(F32 val) +{ +    setValue(SETTING_CLOUD_SHADOW, val); +} + +F32 LLSettingsSky::getCloudVariance() const +{ +    return mSettings[SETTING_CLOUD_VARIANCE].asReal(); +} + +void LLSettingsSky::setCloudVariance(F32 val) +{ +    setValue(SETTING_CLOUD_VARIANCE, val); +} + +F32 LLSettingsSky::getDomeOffset() const +{ +    //return mSettings[SETTING_DOME_OFFSET].asReal(); +    return DOME_OFFSET;     +} + +F32 LLSettingsSky::getDomeRadius() const +{ +    //return mSettings[SETTING_DOME_RADIUS].asReal(); +    return DOME_RADIUS;     +} + +F32 LLSettingsSky::getGamma() const +{ +    return mSettings[SETTING_GAMMA].asReal(); +} + +void LLSettingsSky::setGamma(F32 val) +{ +    mSettings[SETTING_GAMMA] = LLSD::Real(val); +    setDirtyFlag(true); +} + +LLColor3 LLSettingsSky::getGlow() const +{ +    return LLColor3(mSettings[SETTING_GLOW]); +} + +void LLSettingsSky::setGlow(const LLColor3 &val) +{ +    setValue(SETTING_GLOW, val); +} + +F32 LLSettingsSky::getMaxY() const +{ +    return mSettings[SETTING_MAX_Y].asReal(); +} + +void LLSettingsSky::setMaxY(F32 val)  +{ +    setValue(SETTING_MAX_Y, val); +} + +LLQuaternion LLSettingsSky::getMoonRotation() const +{ +    return LLQuaternion(mSettings[SETTING_MOON_ROTATION]); +} + +void LLSettingsSky::setMoonRotation(const LLQuaternion &val) +{ +    setValue(SETTING_MOON_ROTATION, val); +} + +F32 LLSettingsSky::getMoonScale() const +{ +    return mSettings[SETTING_MOON_SCALE].asReal(); +} + +void LLSettingsSky::setMoonScale(F32 val) +{ +    setValue(SETTING_MOON_SCALE, val); +} + +LLUUID LLSettingsSky::getMoonTextureId() const +{ +    return mSettings[SETTING_MOON_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setMoonTextureId(LLUUID id) +{ +    setValue(SETTING_MOON_TEXTUREID, id); +} + +F32  LLSettingsSky::getMoonBrightness() const +{ +    return mSettings[SETTING_MOON_BRIGHTNESS].asReal(); +} + +void LLSettingsSky::setMoonBrightness(F32 brightness_factor) +{ +    setValue(SETTING_MOON_BRIGHTNESS, brightness_factor); +} + +F32 LLSettingsSky::getStarBrightness() const +{ +    return mSettings[SETTING_STAR_BRIGHTNESS].asReal(); +} + +void LLSettingsSky::setStarBrightness(F32 val) +{ +    setValue(SETTING_STAR_BRIGHTNESS, val); +} + +LLColor3 LLSettingsSky::getSunlightColor() const +{ +    return LLColor3(mSettings[SETTING_SUNLIGHT_COLOR]); +} + +LLColor3 LLSettingsSky::getSunlightColorClamped() const +{ +    LLColor3 sunlight = getSunlightColor(); +    //clampColor(sunlight, getGamma(), 3.0f); + +    F32 max_color = llmax(sunlight.mV[0], sunlight.mV[1], sunlight.mV[2]); +    if (max_color > 1.0f) +    { +        sunlight *= 1.0f/max_color; +    } + +    return sunlight; +} + +void LLSettingsSky::setSunlightColor(const LLColor3 &val) +{ +    setValue(SETTING_SUNLIGHT_COLOR, val); +} + +LLQuaternion LLSettingsSky::getSunRotation() const +{ +    return LLQuaternion(mSettings[SETTING_SUN_ROTATION]); +} + +void LLSettingsSky::setSunRotation(const LLQuaternion &val)  +{ +    setValue(SETTING_SUN_ROTATION, val); +} + + +F32 LLSettingsSky::getSunScale() const +{ +    return mSettings[SETTING_SUN_SCALE].asReal(); +} + +void LLSettingsSky::setSunScale(F32 val) +{ +    setValue(SETTING_SUN_SCALE, val); +} + +LLUUID LLSettingsSky::getSunTextureId() const +{ +    return mSettings[SETTING_SUN_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setSunTextureId(LLUUID id)  +{ +    setValue(SETTING_SUN_TEXTUREID, id); +} + +LLUUID LLSettingsSky::getNextSunTextureId() const +{ +    return mNextSunTextureId; +} + +LLUUID LLSettingsSky::getNextMoonTextureId() const +{ +    return mNextMoonTextureId; +} + +LLUUID LLSettingsSky::getNextCloudNoiseTextureId() const +{ +    return mNextCloudTextureId; +} + +LLUUID LLSettingsSky::getNextBloomTextureId() const +{ +    return mNextBloomTextureId; +} + diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h new file mode 100644 index 0000000000..4127911643 --- /dev/null +++ b/indra/llinventory/llsettingssky.h @@ -0,0 +1,374 @@ +/** +* @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" + +const F32 EARTH_RADIUS  =      6.370e6f; +const F32 SUN_RADIUS    =    695.508e6f; +const F32 SUN_DIST      = 149598.260e6f; +const F32 MOON_RADIUS   =      1.737e6f; +const F32 MOON_DIST     =    384.400e6f; + +class LLSettingsSky: public LLSettingsBase +{ +public: +    static const std::string SETTING_AMBIENT; +    static const std::string SETTING_BLOOM_TEXTUREID; +    static const std::string SETTING_RAINBOW_TEXTUREID; +    static const std::string SETTING_HALO_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_CLOUD_VARIANCE; + +    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_SCALE; +    static const std::string SETTING_MOON_TEXTUREID; +    static const std::string SETTING_MOON_BRIGHTNESS; + +    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_SCALE; +    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_MIE_ANISOTROPY_FACTOR; + +    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_SKY_MOISTURE_LEVEL; +    static const std::string SETTING_SKY_DROPLET_RADIUS; +    static const std::string SETTING_SKY_ICE_LEVEL; + +    static const std::string SETTING_LEGACY_HAZE; + +    static const LLUUID DEFAULT_ASSET_ID; + +    typedef PTR_NAMESPACE::shared_ptr<LLSettingsSky> ptr_t; + +    //--------------------------------------------------------------------- +    LLSettingsSky(const LLSD &data); +    virtual ~LLSettingsSky() { }; + +    virtual ptr_t   buildClone() const = 0; + +    //--------------------------------------------------------------------- +    virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("sky"); } +    virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_SKY; } + +    // Settings status  +    virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE; + +    virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE; + +    void replaceWithSky(LLSettingsSky::ptr_t pother); +    static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f); + +    F32 getPlanetRadius() const; +    F32 getSkyBottomRadius() const; +    F32 getSkyTopRadius() const; +    F32 getSunArcRadians() const; +    F32 getMieAnisotropy() const;    + +    F32 getSkyMoistureLevel() const; +    F32 getSkyDropletRadius() const; +    F32 getSkyIceLevel() const; + +    // Return first (only) profile layer represented in LLSD +    LLSD getRayleighConfig() const; +    LLSD getMieConfig() const; +    LLSD getAbsorptionConfig() const; + +    // Return entire LLSDArray of profile layers represented in LLSD +    LLSD getRayleighConfigs() const; +    LLSD getMieConfigs() const; +    LLSD getAbsorptionConfigs() const; + +    LLUUID getBloomTextureId() const; +    LLUUID getRainbowTextureId() const; +    LLUUID getHaloTextureId() const; + +    void setRayleighConfigs(const LLSD& rayleighConfig); +    void setMieConfigs(const LLSD& mieConfig); +    void setAbsorptionConfigs(const LLSD& absorptionConfig); + +    void setPlanetRadius(F32 radius); +    void setSkyBottomRadius(F32 radius); +    void setSkyTopRadius(F32 radius); +    void setSunArcRadians(F32 radians); +    void setMieAnisotropy(F32 aniso_factor); + +    void setSkyMoistureLevel(F32 moisture_level); +    void setSkyDropletRadius(F32 radius); +    void setSkyIceLevel(F32 ice_level); + +    //--------------------------------------------------------------------- +    LLColor3 getAmbientColor() const; +    void setAmbientColor(const LLColor3 &val); + +    LLColor3 getCloudColor() const; +    void setCloudColor(const LLColor3 &val); + +    LLUUID getCloudNoiseTextureId() const; +    void setCloudNoiseTextureId(const LLUUID &id); + +    LLColor3 getCloudPosDensity1() const; +    void setCloudPosDensity1(const LLColor3 &val); + +    LLColor3 getCloudPosDensity2() const; +    void setCloudPosDensity2(const LLColor3 &val); + +    F32 getCloudScale() const; +    void setCloudScale(F32 val); + +    LLVector2 getCloudScrollRate() const; +    void setCloudScrollRate(const LLVector2 &val); + +    void setCloudScrollRateX(F32 val); +    void setCloudScrollRateY(F32 val); + +    F32 getCloudShadow() const; +    void setCloudShadow(F32 val); +     +    F32 getCloudVariance() const; +    void setCloudVariance(F32 val); + +    F32 getDomeOffset() const; +    F32 getDomeRadius() const; + +    F32 getGamma() const; + +    void setGamma(F32 val); + +    LLColor3 getGlow() const; +    void setGlow(const LLColor3 &val); + +    F32 getMaxY() const; + +    void setMaxY(F32 val); + +    LLQuaternion getMoonRotation() const; +    void setMoonRotation(const LLQuaternion &val); + +    F32 getMoonScale() const; +    void setMoonScale(F32 val); + +    LLUUID getMoonTextureId() const; +    void setMoonTextureId(LLUUID id); + +    F32  getMoonBrightness() const; +    void setMoonBrightness(F32 brightness_factor); + +    F32 getStarBrightness() const; +    void setStarBrightness(F32 val); + +    LLColor3 getSunlightColor() const; +    void setSunlightColor(const LLColor3 &val); + +    LLQuaternion getSunRotation() const; +    void setSunRotation(const LLQuaternion &val) ; + +    F32 getSunScale() const; +    void setSunScale(F32 val); + +    LLUUID getSunTextureId() const; +    void setSunTextureId(LLUUID id); + +    //===================================================================== +    // transient properties used in animations. +    LLUUID getNextSunTextureId() const; +    LLUUID getNextMoonTextureId() const; +    LLUUID getNextCloudNoiseTextureId() const; +    LLUUID getNextBloomTextureId() const; + +    //===================================================================== +    virtual void loadTextures() { }; + +    //===================================================================== +    virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE; +    static validation_list_t validationList(); + +    static LLSD translateLegacySettings(const LLSD& legacy); + +// LEGACY_ATMOSPHERICS +    static LLSD translateLegacyHazeSettings(const LLSD& legacy); + +    LLColor3 getLightAttenuation(F32 distance) const; +    LLColor3 getLightTransmittance(F32 distance) const; +    LLColor3 getTotalDensity() const; +    LLColor3 gammaCorrect(const LLColor3& in) const; + +    LLColor3 getBlueDensity() const; +    LLColor3 getBlueHorizon() const; +    F32 getHazeDensity() const; +    F32 getHazeHorizon() const; +    F32 getDensityMultiplier() const; +    F32 getDistanceMultiplier() const; + +    void setBlueDensity(const LLColor3 &val); +    void setBlueHorizon(const LLColor3 &val); +    void setDensityMultiplier(F32 val); +    void setDistanceMultiplier(F32 val); +    void setHazeDensity(F32 val); +    void setHazeHorizon(F32 val); + +// Internal/calculated settings +    bool getIsSunUp() const; +    bool getIsMoonUp() const; + +    // determines how much the haze glow effect occurs in rendering +    F32 getSunMoonGlowFactor() const; + +    LLVector3 getLightDirection() const; +    LLColor3  getLightDiffuse() const; + +    LLVector3 getSunDirection() const; +    LLVector3 getMoonDirection() const; + +    // color based on brightness +    LLColor3  getMoonlightColor() const; +     +    LLColor4  getMoonAmbient() const; +    LLColor3  getMoonDiffuse() const; +    LLColor4  getSunAmbient() const; +    LLColor3  getSunDiffuse() const; +    LLColor4  getTotalAmbient() const; +    LLColor4  getHazeColor() const; + +    LLColor3 getSunlightColorClamped() const; +    LLColor3 getAmbientColorClamped() const; + +    virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } + +    static LLUUID GetDefaultAssetId(); +    static LLUUID GetDefaultSunTextureId(); +    static LLUUID GetBlankSunTextureId(); +    static LLUUID GetDefaultMoonTextureId(); +    static LLUUID GetDefaultCloudNoiseTextureId(); +    static LLUUID GetDefaultBloomTextureId(); +    static LLUUID GetDefaultRainbowTextureId(); +    static LLUUID GetDefaultHaloTextureId(); + +    static LLSD createDensityProfileLayer( +                    F32 width, +                    F32 exponential_term, +                    F32 exponential_scale_factor, +                    F32 linear_term, +                    F32 constant_term, +                    F32 aniso_factor = 0.0f); + +    static LLSD createSingleLayerDensityProfile( +                    F32 width, +                    F32 exponential_term, +                    F32 exponential_scale_factor, +                    F32 linear_term, +                    F32 constant_term, +                    F32 aniso_factor = 0.0f); + +    virtual void        updateSettings() SETTINGS_OVERRIDE; +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 SETTINGS_OVERRIDE; +    virtual stringset_t getSkipInterpolateKeys() const SETTINGS_OVERRIDE; + +    LLUUID      mNextSunTextureId; +    LLUUID      mNextMoonTextureId; +    LLUUID      mNextCloudTextureId; +    LLUUID      mNextBloomTextureId; +    LLUUID      mNextRainbowTextureId; +    LLUUID      mNextHaloTextureId; + +private: +    static LLSD rayleighConfigDefault(); +    static LLSD absorptionConfigDefault(); +    static LLSD mieConfigDefault(); + +    LLColor3 getColor(const std::string& key, const LLColor3& default_value) const; +    F32      getFloat(const std::string& key, F32 default_value) const; + +    void        calculateHeavenlyBodyPositions() const; +    void        calculateLightSettings() const; +    void        clampColor(LLColor3& color, F32 gamma, const F32 scale = 1.0f) const; + +    mutable LLVector3   mSunDirection; +    mutable LLVector3   mMoonDirection; +    mutable LLVector3   mLightDirection; + +    static const F32 DOME_RADIUS; +    static const F32 DOME_OFFSET; + +    mutable LLColor4    mMoonAmbient; +    mutable LLColor3    mMoonDiffuse; +    mutable LLColor4    mSunAmbient; +    mutable LLColor3    mSunDiffuse; +    mutable LLColor4    mTotalAmbient; +    mutable LLColor4    mHazeColor; + +    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..0eb95dcd89 --- /dev/null +++ b/indra/llinventory/llsettingswater.cpp @@ -0,0 +1,304 @@ +/** +* @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_MULTIPLIER("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_TRANSPARENT_TEXTURE("transparent_texture"); +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_MULTIPLIER("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_ASSET_ID("59d1a851-47e7-0e5f-1ed7-6b715154f41a"); + +static const LLUUID DEFAULT_TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +static const LLUUID DEFAULT_OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055"); + +//========================================================================= +LLSettingsWater::LLSettingsWater(const LLSD &data) : +    LLSettingsBase(data), +    mNextNormalMapID() +{ +} + +LLSettingsWater::LLSettingsWater() : +    LLSettingsBase(), +    mNextNormalMapID() +{ +} + +//========================================================================= +LLSD LLSettingsWater::defaults(const LLSettingsBase::TrackPosition& position) +{ +    static LLSD dfltsetting; + +    if (dfltsetting.size() == 0) +    { +        // give the normal scale offset some variability over track time... +        F32 normal_scale_offset = (position * 0.5f) - 0.25f; + +        // Magic constants copied form defaults.xml  +        dfltsetting[SETTING_BLUR_MULTIPLIER] = 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_TRANSPARENT_TEXTURE] = GetDefaultTransparentTextureAssetId(); +        dfltsetting[SETTING_NORMAL_MAP] = GetDefaultWaterNormalAssetId(); +        dfltsetting[SETTING_NORMAL_SCALE] = LLVector3(2.0f + normal_scale_offset, 2.0f + normal_scale_offset, 2.0f + normal_scale_offset).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) +{ +    bool converted_something(false); +    LLSD newsettings(defaults()); + +    if (legacy.has(SETTING_LEGACY_BLUR_MULTIPLIER)) +    { +        newsettings[SETTING_BLUR_MULTIPLIER] = LLSD::Real(legacy[SETTING_LEGACY_BLUR_MULTIPLIER].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_FOG_COLOR)) +    { +        newsettings[SETTING_FOG_COLOR] = LLColor3(legacy[SETTING_LEGACY_FOG_COLOR]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_FOG_DENSITY)) +    { +        newsettings[SETTING_FOG_DENSITY] = LLSD::Real(legacy[SETTING_LEGACY_FOG_DENSITY]); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_FOG_MOD)) +    { +        newsettings[SETTING_FOG_MOD] = LLSD::Real(legacy[SETTING_LEGACY_FOG_MOD].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_FRESNEL_OFFSET)) +    { +        newsettings[SETTING_FRESNEL_OFFSET] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_OFFSET].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_FRESNEL_SCALE)) +    { +        newsettings[SETTING_FRESNEL_SCALE] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_SCALE].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_NORMAL_MAP)) +    { +        newsettings[SETTING_NORMAL_MAP] = LLSD::UUID(legacy[SETTING_LEGACY_NORMAL_MAP].asUUID()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_NORMAL_SCALE)) +    { +        newsettings[SETTING_NORMAL_SCALE] = LLVector3(legacy[SETTING_LEGACY_NORMAL_SCALE]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_SCALE_ABOVE)) +    { +        newsettings[SETTING_SCALE_ABOVE] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_ABOVE].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_SCALE_BELOW)) +    { +        newsettings[SETTING_SCALE_BELOW] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_BELOW].asReal()); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_WAVE1_DIR)) +    { +        newsettings[SETTING_WAVE1_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE1_DIR]).getValue(); +        converted_something |= true; +    } +    if (legacy.has(SETTING_LEGACY_WAVE2_DIR)) +    { +        newsettings[SETTING_WAVE2_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE2_DIR]).getValue(); +        converted_something |= true; +    } + +    if (!converted_something) +        return LLSD(); +    return newsettings; +} + +void LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F64 blendf)  +{ +    LLSettingsWater::ptr_t other = PTR_NAMESPACE::static_pointer_cast<LLSettingsWater>(end); +    if (other) +    { +        LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf); +        replaceSettings(blenddata); +        mNextNormalMapID = other->getNormalMapID(); +        mNextTransparentTextureID = other->getTransparentTextureID(); +    } +    else +    { +        LL_WARNS("SETTINGS") << "Could not cast end settings to water. No blend performed." << LL_ENDL; +    } +    setBlendFactor(blendf); +} + +void LLSettingsWater::replaceSettings(LLSD settings) +{ +    LLSettingsBase::replaceSettings(settings); +    mNextNormalMapID.setNull(); +    mNextTransparentTextureID.setNull(); +} + +void LLSettingsWater::replaceWithWater(LLSettingsWater::ptr_t other) +{ +    replaceWith(other); + +    mNextNormalMapID = other->mNextNormalMapID; +    mNextTransparentTextureID = other->mNextTransparentTextureID; +} + +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_MULTIPLIER, true, LLSD::TypeReal, +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-0.5f)(0.5f))))); +        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(-10.0f)(10.0f))))); +        validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal, +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.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)(3.0f))))); +        validation.push_back(Validator(SETTING_SCALE_BELOW, true, LLSD::TypeReal, +            boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f))))); +        validation.push_back(Validator(SETTING_WAVE1_DIR, true, LLSD::TypeArray, +            boost::bind(&Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(-20.0f)(-20.0f)), +                LLSD(LLSDArray(20.0f)(20.0f))))); +        validation.push_back(Validator(SETTING_WAVE2_DIR, true, LLSD::TypeArray, +            boost::bind(&Validator::verifyVectorMinMax, _1, +                LLSD(LLSDArray(-20.0f)(-20.0f)), +                LLSD(LLSDArray(20.0f)(20.0f))))); +    } + +    return validation; +} + +LLUUID LLSettingsWater::GetDefaultAssetId() +{ +    return DEFAULT_ASSET_ID; +} + +LLUUID LLSettingsWater::GetDefaultWaterNormalAssetId() +{ +    return DEFAULT_WATER_NORMAL; +} + +LLUUID LLSettingsWater::GetDefaultTransparentTextureAssetId() +{ +    return DEFAULT_TRANSPARENT_WATER_TEXTURE; +} + +LLUUID LLSettingsWater::GetDefaultOpaqueTextureAssetId() +{ +    return DEFAULT_OPAQUE_WATER_TEXTURE; +} + +F32 LLSettingsWater::getModifiedWaterFogDensity(bool underwater) const +{ +    F32 fog_density = getWaterFogDensity(); +    F32 underwater_fog_mod = getFogMod(); +    if (underwater && underwater_fog_mod > 0.0f) +    {         +        underwater_fog_mod = llclamp(underwater_fog_mod, 0.0f, 10.0f); +        fog_density = pow(fog_density, underwater_fog_mod); +    } +    return fog_density; +} diff --git a/indra/llinventory/llsettingswater.h b/indra/llinventory/llsettingswater.h new file mode 100644 index 0000000000..e0bfd29f2d --- /dev/null +++ b/indra/llinventory/llsettingswater.h @@ -0,0 +1,249 @@ +/** +* @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_MULTIPLIER; +    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_TRANSPARENT_TEXTURE; +    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_ASSET_ID; + +    typedef PTR_NAMESPACE::shared_ptr<LLSettingsWater> ptr_t; + +    //--------------------------------------------------------------------- +    LLSettingsWater(const LLSD &data); +    virtual ~LLSettingsWater() { }; + +    virtual ptr_t   buildClone() const = 0; + +    //--------------------------------------------------------------------- +    virtual std::string     getSettingsType() const SETTINGS_OVERRIDE { return std::string("water"); } +    virtual LLSettingsType::type_e  getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_WATER; } + +    // Settings status  +    virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE; + +    virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE; +    void replaceWithWater(LLSettingsWater::ptr_t other); + +    static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f); + +    //--------------------------------------------------------------------- +    F32 getBlurMultiplier() const +    {    +        return mSettings[SETTING_BLUR_MULTIPLIER].asReal(); +    } + +    void setBlurMultiplier(F32 val) +    { +        setValue(SETTING_BLUR_MULTIPLIER, val); +    } + +    LLColor3 getWaterFogColor() const +    { +        return LLColor3(mSettings[SETTING_FOG_COLOR]); +    } + +    void setWaterFogColor(LLColor3 val) +    { +        setValue(SETTING_FOG_COLOR, val); +    } + +    F32 getWaterFogDensity() const +    { +        return mSettings[SETTING_FOG_DENSITY].asReal(); +    } + +    F32 getModifiedWaterFogDensity(bool underwater) const; + +    void setWaterFogDensity(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 getTransparentTextureID() const +    { +        return mSettings[SETTING_TRANSPARENT_TEXTURE].asUUID(); +    } + +    void setTransparentTextureID(LLUUID val) +    { +        setValue(SETTING_TRANSPARENT_TEXTURE, 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); +    } + +    //------------------------------------------- +    LLUUID getNextNormalMapID() const +    { +        return mNextNormalMapID; +    } + +    LLUUID getNextTransparentTextureID() const +    { +        return mNextTransparentTextureID; +    } + +    virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE; +    static validation_list_t validationList(); + +    static LLSD         translateLegacySettings(LLSD legacy); + +    virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } + +    static LLUUID GetDefaultAssetId(); +    static LLUUID GetDefaultWaterNormalAssetId(); +    static LLUUID GetDefaultTransparentTextureAssetId(); +    static LLUUID GetDefaultOpaqueTextureAssetId(); + +protected: +    static const std::string SETTING_LEGACY_BLUR_MULTIPLIER; +    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(); + +    LLUUID    mNextTransparentTextureID; +    LLUUID    mNextNormalMapID; + +}; + +#endif | 
