123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- /**
- * @file llsettingsbase.cpp
- * @brief A base class for asset based settings groups.
- *
- * $LicenseInfo:firstyear=2018&license=viewergpl$
- *
- * Copyright (c) 2001-2019, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include <ostream>
- #include <sstream>
- #include "llsettingsbase.h"
- #include "llsdserialize.h"
- #define VALIDATION_DEBUG 0
- constexpr F32 BREAK_POINT = 0.5f;
- 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";
- std::ostream& operator<<(std::ostream& os, LLSettingsBase& settings)
- {
- LLSDSerialize::serialize(settings.getSettings(), os,
- LLSDSerialize::LLSD_NOTATION);
- return os;
- }
- LLSettingsBase::LLSettingsBase()
- : mSettings(LLSD::emptyMap()),
- mBlendedFactor(0.0),
- mDirty(true)
- {
- }
- LLSettingsBase::LLSettingsBase(const LLSD& setting)
- : mSettings(setting),
- mBlendedFactor(0.0),
- mDirty(true)
- {
- }
- 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 new_settings;
- for (LLSD::map_const_iterator it = settings.beginMap(),
- end = settings.endMap();
- it != end; ++it)
- {
- const std::string& key_name = it->first;
- const LLSD& value = it->second;
- LLSD::Type setting_type = value.type();
- switch (setting_type)
- {
- case LLSD::TypeMap:
- new_settings[key_name] = combineSDMaps(value, LLSD());
- break;
- case LLSD::TypeArray:
- new_settings[key_name] = LLSD::emptyArray();
- for (LLSD::array_const_iterator ita = value.beginArray(),
- enda = value.endArray();
- ita != enda; ++ita)
- {
- new_settings[key_name].append(*ita);
- }
- break;
- default:
- new_settings[key_name] = value;
- }
- }
- if (!other.isUndefined())
- {
- for (LLSD::map_const_iterator it = other.beginMap(),
- end = other.endMap();
- it !=end; ++it)
- {
- const std::string& key_name = it->first;
- const LLSD& value = it->second;
- LLSD::Type setting_type = value.type();
- switch (setting_type)
- {
- case LLSD::TypeMap:
- new_settings[key_name] = combineSDMaps(value, LLSD());
- break;
- case LLSD::TypeArray:
- new_settings[key_name] = LLSD::emptyArray();
- for (LLSD::array_const_iterator ita = value.beginArray(),
- enda = value.endArray();
- ita != enda; ++ita)
- {
- new_settings[key_name].append(*ita);
- }
- break;
- default:
- new_settings[key_name] = value;
- }
- }
- }
- return new_settings;
- }
- LLSD LLSettingsBase::interpolateSDMap(const LLSD& settings, const LLSD& other,
- const parammapping_t& defaults,
- F64 mix) const
- {
- llassert(mix >= 0.f && mix <= 1.f);
- LLSD new_settings;
- const stringset_t& skip = getSkipInterpolateKeys();
- const stringset_t& slerps = getSlerpKeys();
- for (LLSD::map_const_iterator it = settings.beginMap(),
- end = settings.endMap();
- it != end; ++it)
- {
- const std::string& key_name = it->first;
- if (skip.find(key_name) != skip.end())
- {
- continue;
- }
- const LLSD& value = it->second;
- LLSD other_value;
- if (other.has(key_name))
- {
- other_value = other[key_name];
- }
- else
- {
- parammapping_t::const_iterator def_it = defaults.find(key_name);
- if (def_it != defaults.end())
- {
- other_value = def_it->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: blend this out instead ?
- new_settings[key_name] = value;
- continue;
- }
- }
- new_settings[key_name] = interpolateSDValue(key_name, value,
- other_value, defaults, mix,
- slerps);
- }
- // Special handling cases
- if (settings.has(SETTING_FLAGS))
- {
- U32 flags = (U32)settings[SETTING_FLAGS].asInteger();
- if (other.has(SETTING_FLAGS))
- {
- flags |= (U32)other[SETTING_FLAGS].asInteger();
- }
- new_settings[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(), end = other.endMap();
- it != end; ++it)
- {
- const std::string& key_name = it->first;
- if (skip.find(key_name) != skip.end() || settings.has(key_name))
- {
- continue;
- }
- parammapping_t::const_iterator def_it = defaults.find(key_name);
- if (def_it != defaults.end())
- {
- // Blend against default value
- new_settings[key_name] =
- interpolateSDValue(key_name, def_it->second.getDefaultValue(),
- it->second, defaults, mix, slerps);
- }
- else if (it->second.type() == LLSD::TypeMap)
- {
- // Interpolate in case there are defaults inside (part of legacy)
- new_settings[key_name] = interpolateSDValue(key_name, LLSDMap(),
- it->second, defaults,
- mix, slerps);
- }
- // Else do nothing when no known defaults. *TODO: blend out instead ?
- }
- // Note: writes variables from skip list: bug ?
- for (LLSD::map_const_iterator it = other.beginMap(), end = other.endMap();
- it != end; ++it)
- {
- // *TODO: blend this in instead ?
- if (skip.find(it->first) == skip.end())
- {
- continue;
- }
- if (settings.has(it->first))
- {
- new_settings[it->first] = it->second;
- }
- }
- return new_settings;
- }
- LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name,
- const LLSD& value,
- const LLSD& other_value,
- const parammapping_t& defaults,
- F64 mix,
- const stringset_t& slerps) const
- {
- 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.
- llwarns << "Setting lerp between mismatched types for '" << key_name
- << "'." << llendl;
- return mix > BREAK_POINT ? other_value : value;
- }
- LLSD new_value;
- switch (setting_type)
- {
- case LLSD::TypeInteger:
- // lerp between the two values rounding the result to the nearest
- // integer
- new_value = LLSD::Integer(ll_round(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.
- for (U32 i = 0, len = llmax(value.size(), other_value.size());
- 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;
- 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;
- }
- return new_value;
- }
- //virtual
- const LLSettingsBase::stringset_t& LLSettingsBase::getSkipInterpolateKeys() const
- {
- static stringset_t skip_set;
- if (skip_set.empty())
- {
- skip_set.emplace(SETTING_FLAGS);
- skip_set.emplace(SETTING_HASH);
- }
- return skip_set;
- }
- //virtual
- const LLSettingsBase::stringset_t& LLSettingsBase::getSlerpKeys() const
- {
- static stringset_t slerp_keys;
- return slerp_keys;
- }
- //virtual
- const LLSettingsBase::parammapping_t& LLSettingsBase::getParameterMap() const
- {
- static parammapping_t param_mapping;
- return param_mapping;
- }
- 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));
- return hash_value(hash_settings);
- }
- bool LLSettingsBase::validate()
- {
- const 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)
- {
- llwarns << "Validation errors: " << result["errors"] << llendl;
- }
- if (result["warnings"].size() > 0)
- {
- LL_DEBUGS("EnvSettings") << "Validation warnings: "
- << result["warnings"] << LL_ENDL;
- }
- return result["success"].asBoolean();
- }
- LLSD LLSettingsBase::settingValidation(LLSD& settings,
- const validation_list_t& validations,
- bool partial)
- {
- static Validator validateName(SETTING_NAME, false, LLSD::TypeString,
- boost::bind(&Validator::verifyStringLength,
- _1, _2, 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, strip;
- bool is_valid = 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'."));
- is_valid = false;
- }
- validated.emplace(validateName.getName());
- if (!validateId.verify(settings, flags))
- {
- errors.append(LLSD::String("Unable to validate 'id'."));
- is_valid = false;
- }
- validated.emplace(validateId.getName());
- if (!validateHash.verify(settings, flags))
- {
- errors.append(LLSD::String("Unable to validate 'hash'."));
- is_valid = false;
- }
- validated.emplace(validateHash.getName());
- if (!validateAssetId.verify(settings, flags))
- {
- errors.append(LLSD::String("Invalid asset Id"));
- is_valid = false;
- }
- validated.emplace(validateAssetId.getName());
- if (!validateType.verify(settings, flags))
- {
- errors.append(LLSD::String("Unable to validate 'type'."));
- is_valid = false;
- }
- validated.emplace(validateType.getName());
- if (!validateFlags.verify(settings, flags))
- {
- errors.append(LLSD::String("Unable to validate 'flags'."));
- is_valid = false;
- }
- validated.emplace(validateFlags.getName());
- // Fields for specific settings.
- for (validation_list_t::const_iterator it = validations.begin(),
- end = validations.end();
- it != end; ++it)
- {
- #if VALIDATION_DEBUG
- LLSD oldvalue;
- if (settings.has(it->getName()))
- {
- oldvalue = llsd_clone(mSettings[it->getName()]);
- }
- #endif
- if (!it->verify(settings, flags))
- {
- std::stringstream errtext;
- errtext << "Settings LLSD fails validation and could not be corrected for '"
- << it->getName() << "'!\n";
- errors.append(errtext.str());
- is_valid = false;
- }
- validated.emplace(it->getName());
- #if VALIDATION_DEBUG
- if (!oldvalue.isUndefined() && !compare_llsd(settings[it->getName()],
- oldvalue))
- {
- llwarns << "Setting '" << it->getName() << "' was changed: "
- << oldvalue << " -> " << settings[it->getName()] << llendl;
- }
- #endif
- }
- // Strip extra entries
- for (LLSD::map_const_iterator it = settings.beginMap(),
- end = settings.endMap();
- it != end; ++it)
- {
- if (validated.find(it->first) == validated.end())
- {
- std::stringstream warntext;
- warntext << "Stripping setting '" << it->first << "'";
- warnings.append( warntext.str() );
- strip.emplace(it->first);
- }
- }
- for (stringset_t::iterator it = strip.begin(), end = strip.end();
- it != end; ++it)
- {
- settings.erase(*it);
- }
- return LLSDMap("success",
- LLSD::Boolean(is_valid))("errors", errors)("warnings", warnings);
- }
- bool LLSettingsBase::Validator::verify(LLSD& data, U32 flags) const
- {
- if (!data.has(mName) || (data.has(mName) && data[mName].isUndefined()))
- {
- if (flags & VALIDATION_PARTIAL)
- {
- // 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)
- {
- llwarns << "Missing required setting '" << mName
- << "' with no default." << llendl;
- }
- return !mRequired;
- }
- if (data[mName].type() != mType)
- {
- llwarns << "Setting '" << mName << "' is incorrect type." << llendl;
- return false;
- }
- if (!mVerify.empty() && !mVerify(data[mName], flags))
- {
- llwarns << "Setting '" << mName << "' fails validation." << llendl;
- return false;
- }
- return true;
- }
- bool LLSettingsBase::Validator::verifyColor(LLSD& value, U32)
- {
- return value.size() == 3 || value.size() == 4;
- }
- bool LLSettingsBase::Validator::verifyVector(LLSD& value, U32, size_t length)
- {
- return value.size() == length;
- }
- bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD& value, U32,
- size_t length)
- {
- if (value.size() != length)
- {
- return false;
- }
- LLSD newvector;
- switch (length)
- {
- case 2:
- {
- LLVector2 vect(value);
- if (is_approx_equal(vect.normalize(), 1.f))
- {
- return true;
- }
- newvector = vect.getValue();
- break;
- }
- case 3:
- {
- LLVector3 vect(value);
- if (is_approx_equal(vect.normalize(), 1.f))
- {
- return true;
- }
- newvector = vect.getValue();
- break;
- }
- case 4:
- {
- LLVector4 vect(value);
- if (is_approx_equal(vect.normalize(), 1.f))
- {
- return true;
- }
- newvector = vect.getValue();
- break;
- }
- default:
- return false;
- }
- for (size_t index = 0; index < length; ++index)
- {
- value[index] = newvector[index];
- }
- return true;
- }
- bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD& value, U32,
- LLSD minvals, LLSD maxvals)
- {
- for (U32 index = 0, count = value.size(); index < count; ++index)
- {
- if (minvals[index].asString() != "*" &&
- minvals[index].asReal() > value[index].asReal())
- {
- value[index] = minvals[index].asReal();
- }
- if (maxvals[index].asString() != "*" &&
- maxvals[index].asReal() < value[index].asReal())
- {
- value[index] = maxvals[index].asReal();
- }
- }
- return true;
- }
- bool LLSettingsBase::Validator::verifyQuaternion(LLSD& value, U32)
- {
- return value.size() == 4;
- }
- bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD& value, U32)
- {
- if (value.size() != 4)
- {
- return false;
- }
- LLQuaternion quat(value);
- if (is_approx_equal(quat.normalize(), 1.f))
- {
- 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, U32, LLSD range)
- {
- F64 real = value.asReal();
- F64 clampedval = llclamp(LLSD::Real(real), range[0].asReal(),
- range[1].asReal());
- if (!is_approx_equal(clampedval, real))
- {
- value = LLSD::Real(clampedval);
- }
- return true;
- }
- bool LLSettingsBase::Validator::verifyIntegerRange(LLSD& value, U32,
- LLSD range)
- {
- S32 ival = value.asInteger();
- S32 clampedval = llclamp(LLSD::Integer(ival), range[0].asInteger(),
- range[1].asInteger());
- if (clampedval != ival)
- {
- value = LLSD::Integer(clampedval);
- }
- return true;
- }
- bool LLSettingsBase::Validator::verifyStringLength(LLSD& value, U32,
- size_t length)
- {
- std::string sval = value.asString();
- if (!sval.empty())
- {
- sval = sval.substr(0, length);
- value = LLSD::String(sval);
- }
- return true;
- }
- void LLSettingsBlender::update(F64 blendf)
- {
- F64 res = setBlendFactor(blendf);
- if (res >= 0.0 && res < 1.0)
- {
- mTarget->update();
- }
- else
- {
- llassert(false);
- }
- }
- F64 LLSettingsBlender::setBlendFactor(F64 blendf_in)
- {
- F32 blendf = blendf_in;
- if (blendf >= 1.f)
- {
- triggerComplete();
- }
- blendf = llclamp(blendf, 0.f, 1.f);
- if (mTarget)
- {
- mTarget->replaceSettings(mInitial->getSettings());
- mTarget->blend(mFinal, blendf);
- }
- else
- {
- llwarns << "No target for settings blender." << llendl;
- }
- return blendf;
- }
- void LLSettingsBlender::triggerComplete()
- {
- if (mTarget)
- {
- mTarget->replaceSettings(mFinal->getSettings());
- }
- // Prevents this from deleting too soon
- LLSettingsBlender::ptr_t hold = shared_from_this();
- mTarget->update();
- mOnFinished(shared_from_this());
- }
- void LLSettingsBlender::reset(LLSettingsBase::ptr_t& initsetting,
- const LLSettingsBase::ptr_t& endsetting, F32)
- {
- // Note: the 'span' reset parameter is unused by the base class.
- if (!mInitial)
- {
- llwarns << "Reseting blender with empty initial setting. Expect badness in the future."
- << llendl;
- }
- mInitial = initsetting;
- mFinal = endsetting;
- if (!mFinal)
- {
- mFinal = mInitial;
- }
- if (mTarget)
- {
- mTarget->replaceSettings(mInitial->getSettings());
- }
- }
- F64 LLSettingsBlenderTimeDelta::calculateBlend(F32 spanpos, F32 spanlen) const
- {
- return fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen;
- }
- bool LLSettingsBlenderTimeDelta::applyTimeDelta(F64 timedelta)
- {
- mTimeSpent += timedelta;
- if (mTimeSpent > mBlendSpan)
- {
- triggerComplete();
- return false;
- }
- F64 blendf = calculateBlend(mTimeSpent, mBlendSpan);
- if (fabs(mLastBlendF - blendf) < mBlendFMinDelta)
- {
- return false;
- }
- mLastBlendF = blendf;
- update(blendf);
- return true;
- }
|